diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index aa43052df7..9845c2ed2a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -38,7 +38,7 @@ jobs: testing: name: Testing - runs-on: windows-2022 + runs-on: ubuntu-22.04 env: NUGET_PACKAGES: ${{ github.workspace }}/.nuget/packages steps: @@ -46,13 +46,10 @@ jobs: uses: actions/setup-dotnet@9211491ffb35dd6a6657ca4f45d43dfe6e97c829 with: dotnet-version: "6.0.x" - - name: Set up MSBuild - uses: microsoft/setup-msbuild@ab534842b4bdf384b8aaf93765dc6f721d9f5fab - name: Print environment run: | dotnet --info - msbuild -version nuget help | grep Version echo "GitHub ref: $GITHUB_REF" echo "GitHub event: $GITHUB_EVENT" @@ -64,20 +61,23 @@ jobs: run: dotnet restore --locked-mode shell: pwsh + - name: Remove SQL proj + run: dotnet sln bitwarden-server.sln remove src/Sql/Sql.sqlproj + - name: Build OSS solution - run: msbuild bitwarden-server.sln /p:Configuration=Debug /p:DefineConstants="OSS" /verbosity:minimal + run: dotnet build bitwarden-server.sln -p:Configuration=Debug -p:DefineConstants="OSS" --verbosity minimal shell: pwsh - name: Build solution - run: msbuild bitwarden-server.sln /p:Configuration=Debug /verbosity:minimal + run: dotnet build bitwarden-server.sln -p:Configuration=Debug --verbosity minimal shell: pwsh - name: Test OSS solution - run: dotnet test ./test --configuration Debug --no-build --logger "trx;LogFileName=oss-test-results.trx" || true + run: dotnet test ./test --configuration Debug --no-build --logger "trx;LogFileName=oss-test-results.trx" shell: pwsh - name: Test Bitwarden solution - run: dotnet test ./bitwarden_license/test --configuration Debug --no-build --logger "trx;LogFileName=bw-test-results.trx" || true + run: dotnet test ./bitwarden_license/test --configuration Debug --no-build --logger "trx;LogFileName=bw-test-results.trx" shell: pwsh - name: Report test results @@ -249,6 +249,14 @@ jobs: steps: - name: Checkout repo uses: actions/checkout@a12a3943b4bdde767164f792f33f40b04645d846 + + - name: Set up image tag + run: | + IMAGE_TAG=$(echo "${GITHUB_REF:11}" | sed "s#/#-#g") # slash safe branch name + if [[ "$IMAGE_TAG" == "master" ]]; then + IMAGE_TAG=dev + fi + echo "IMAGE_TAG=$IMAGE_TAG" >> $GITHUB_ENV ########## Build Docker Image ########## - name: Setup project name @@ -277,28 +285,44 @@ jobs: PROJECT_NAME: ${{ steps.setup.outputs.project_name }} run: docker build -t $PROJECT_NAME ${{ matrix.base_path }}/${{ matrix.project_name }} - ########## ACR ########## + ########## QA ACR ########## - name: Login to Azure - QA Subscription uses: Azure/login@1f63701bf3e6892515f1b7ce2d2bf1708b46beaf with: creds: ${{ secrets.AZURE_QA_KV_CREDENTIALS }} - - name: Login to Azure ACR + - name: Login to QA ACR run: az acr login -n bitwardenqa - - name: Tag and Push image to Azure ACR QA registry + - name: Tag and push image to QA ACR env: PROJECT_NAME: ${{ steps.setup.outputs.project_name }} REGISTRY: bitwardenqa.azurecr.io run: | - IMAGE_TAG=$(echo "${GITHUB_REF:11}" | sed "s#/#-#g") # slash safe branch name - if [[ "$IMAGE_TAG" == "master" ]]; then - IMAGE_TAG=dev - fi - docker tag $PROJECT_NAME \ - $REGISTRY/$PROJECT_NAME:$IMAGE_TAG - docker push $REGISTRY/$PROJECT_NAME:$IMAGE_TAG + $REGISTRY/$PROJECT_NAME:${{ env.IMAGE_TAG }} + docker push $REGISTRY/$PROJECT_NAME:${{ env.IMAGE_TAG }} + + - name: Log out of Docker + run: docker logout + + ########## PROD ACR ########## + - name: Login to Azure - PROD Subscription + uses: Azure/login@1f63701bf3e6892515f1b7ce2d2bf1708b46beaf + with: + creds: ${{ secrets.AZURE_PROD_KV_CREDENTIALS }} + + - name: Login to PROD ACR + run: az acr login -n bitwardenprod + + - name: Tag and push image to PROD ACR + env: + PROJECT_NAME: ${{ steps.setup.outputs.project_name }} + REGISTRY: bitwardenprod.azurecr.io + run: | + docker tag $PROJECT_NAME \ + $REGISTRY/$PROJECT_NAME:${{ env.IMAGE_TAG }} + docker push $REGISTRY/$PROJECT_NAME:${{ env.IMAGE_TAG }} - name: Log out of Docker run: docker logout @@ -366,14 +390,9 @@ jobs: PROJECT_NAME: ${{ steps.setup.outputs.project_name }} REGISTRY: bitwarden run: | - IMAGE_TAG=$(echo "${GITHUB_REF:11}" | sed "s#/#-#g") # slash safe branch name - if [[ "$IMAGE_TAG" == "master" ]]; then - IMAGE_TAG=dev - fi - docker tag $PROJECT_NAME \ - $REGISTRY/$PROJECT_NAME:$IMAGE_TAG - docker push $REGISTRY/$PROJECT_NAME:$IMAGE_TAG + $REGISTRY/$PROJECT_NAME:${{ env.IMAGE_TAG }} + docker push $REGISTRY/$PROJECT_NAME:${{ env.IMAGE_TAG }} - name: Log out of Docker and disable Docker Notary if: | diff --git a/.run/Full Server - Self-hosted.run.xml b/.run/Full Server - Self-hosted.run.xml new file mode 100644 index 0000000000..671697cf94 --- /dev/null +++ b/.run/Full Server - Self-hosted.run.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.run/Full Server.run.xml b/.run/Full Server.run.xml new file mode 100644 index 0000000000..2031666f7e --- /dev/null +++ b/.run/Full Server.run.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.run/Min Server - Self-hosted.run.xml b/.run/Min Server - Self-hosted.run.xml new file mode 100644 index 0000000000..ef0ca539d1 --- /dev/null +++ b/.run/Min Server - Self-hosted.run.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/.run/Min Server.run.xml b/.run/Min Server.run.xml new file mode 100644 index 0000000000..6e6cac80a3 --- /dev/null +++ b/.run/Min Server.run.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/bitwarden_license/src/Commercial.Core/SecretsManager/Commands/AccessTokens/CreateAccessTokenCommand.cs b/bitwarden_license/src/Commercial.Core/SecretsManager/Commands/AccessTokens/CreateAccessTokenCommand.cs index e8d179e799..66b525f654 100644 --- a/bitwarden_license/src/Commercial.Core/SecretsManager/Commands/AccessTokens/CreateAccessTokenCommand.cs +++ b/bitwarden_license/src/Commercial.Core/SecretsManager/Commands/AccessTokens/CreateAccessTokenCommand.cs @@ -33,6 +33,12 @@ public class CreateAccessTokenCommand : ICreateAccessTokenCommand } var serviceAccount = await _serviceAccountRepository.GetByIdAsync(apiKey.ServiceAccountId.Value); + + if (!_currentContext.AccessSecretsManager(serviceAccount.OrganizationId)) + { + throw new NotFoundException(); + } + var orgAdmin = await _currentContext.OrganizationAdmin(serviceAccount.OrganizationId); var accessClient = AccessClientHelper.ToAccessClient(_currentContext.ClientType, orgAdmin); @@ -46,7 +52,7 @@ public class CreateAccessTokenCommand : ICreateAccessTokenCommand if (!hasAccess) { - throw new UnauthorizedAccessException(); + throw new NotFoundException(); } apiKey.ClientSecret = CoreHelpers.SecureRandomString(_clientSecretMaxLength); diff --git a/bitwarden_license/src/Commercial.Core/SecretsManager/Commands/Projects/DeleteProjectCommand.cs b/bitwarden_license/src/Commercial.Core/SecretsManager/Commands/Projects/DeleteProjectCommand.cs index 8451f1d40a..e975df93f7 100644 --- a/bitwarden_license/src/Commercial.Core/SecretsManager/Commands/Projects/DeleteProjectCommand.cs +++ b/bitwarden_license/src/Commercial.Core/SecretsManager/Commands/Projects/DeleteProjectCommand.cs @@ -36,7 +36,12 @@ public class DeleteProjectCommand : IDeleteProjectCommand var organizationId = projects.First().OrganizationId; if (projects.Any(p => p.OrganizationId != organizationId)) { - throw new UnauthorizedAccessException(); + throw new BadRequestException(); + } + + if (!_currentContext.AccessSecretsManager(organizationId)) + { + throw new NotFoundException(); } var orgAdmin = await _currentContext.OrganizationAdmin(organizationId); diff --git a/bitwarden_license/src/Commercial.Core/SecretsManager/Commands/Projects/UpdateProjectCommand.cs b/bitwarden_license/src/Commercial.Core/SecretsManager/Commands/Projects/UpdateProjectCommand.cs index 74799547a0..06ed949c0f 100644 --- a/bitwarden_license/src/Commercial.Core/SecretsManager/Commands/Projects/UpdateProjectCommand.cs +++ b/bitwarden_license/src/Commercial.Core/SecretsManager/Commands/Projects/UpdateProjectCommand.cs @@ -26,6 +26,11 @@ public class UpdateProjectCommand : IUpdateProjectCommand throw new NotFoundException(); } + if (!_currentContext.AccessSecretsManager(project.OrganizationId)) + { + throw new NotFoundException(); + } + var orgAdmin = await _currentContext.OrganizationAdmin(project.OrganizationId); var accessClient = AccessClientHelper.ToAccessClient(_currentContext.ClientType, orgAdmin); @@ -38,7 +43,7 @@ public class UpdateProjectCommand : IUpdateProjectCommand if (!hasAccess) { - throw new UnauthorizedAccessException(); + throw new NotFoundException(); } project.Name = updatedProject.Name; diff --git a/bitwarden_license/src/Commercial.Core/SecretsManager/Commands/Secrets/DeleteSecretCommand.cs b/bitwarden_license/src/Commercial.Core/SecretsManager/Commands/Secrets/DeleteSecretCommand.cs index b04a8f911d..c1872717b7 100644 --- a/bitwarden_license/src/Commercial.Core/SecretsManager/Commands/Secrets/DeleteSecretCommand.cs +++ b/bitwarden_license/src/Commercial.Core/SecretsManager/Commands/Secrets/DeleteSecretCommand.cs @@ -1,4 +1,5 @@ -using Bit.Core.Exceptions; +using Bit.Core.Context; +using Bit.Core.Exceptions; using Bit.Core.SecretsManager.Commands.Secrets.Interfaces; using Bit.Core.SecretsManager.Entities; using Bit.Core.SecretsManager.Repositories; @@ -7,10 +8,12 @@ namespace Bit.Commercial.Core.SecretsManager.Commands.Secrets; public class DeleteSecretCommand : IDeleteSecretCommand { + private readonly ICurrentContext _currentContext; private readonly ISecretRepository _secretRepository; - public DeleteSecretCommand(ISecretRepository secretRepository) + public DeleteSecretCommand(ICurrentContext currentContext, ISecretRepository secretRepository) { + _currentContext = currentContext; _secretRepository = secretRepository; } @@ -23,6 +26,18 @@ public class DeleteSecretCommand : IDeleteSecretCommand throw new NotFoundException(); } + // Ensure all secrets belongs to the same organization + var organizationId = secrets.First().OrganizationId; + if (secrets.Any(p => p.OrganizationId != organizationId)) + { + throw new BadRequestException(); + } + + if (!_currentContext.AccessSecretsManager(organizationId)) + { + throw new NotFoundException(); + } + var results = ids.Select(id => { var secret = secrets.FirstOrDefault(secret => secret.Id == id); diff --git a/bitwarden_license/src/Commercial.Core/SecretsManager/Commands/ServiceAccounts/CreateServiceAccountCommand.cs b/bitwarden_license/src/Commercial.Core/SecretsManager/Commands/ServiceAccounts/CreateServiceAccountCommand.cs index f3d3799472..687291d75a 100644 --- a/bitwarden_license/src/Commercial.Core/SecretsManager/Commands/ServiceAccounts/CreateServiceAccountCommand.cs +++ b/bitwarden_license/src/Commercial.Core/SecretsManager/Commands/ServiceAccounts/CreateServiceAccountCommand.cs @@ -1,4 +1,5 @@ -using Bit.Core.SecretsManager.Commands.ServiceAccounts.Interfaces; +using Bit.Core.Repositories; +using Bit.Core.SecretsManager.Commands.ServiceAccounts.Interfaces; using Bit.Core.SecretsManager.Entities; using Bit.Core.SecretsManager.Repositories; @@ -6,15 +7,34 @@ namespace Bit.Commercial.Core.SecretsManager.Commands.ServiceAccounts; public class CreateServiceAccountCommand : ICreateServiceAccountCommand { + private readonly IAccessPolicyRepository _accessPolicyRepository; + private readonly IOrganizationUserRepository _organizationUserRepository; private readonly IServiceAccountRepository _serviceAccountRepository; - public CreateServiceAccountCommand(IServiceAccountRepository serviceAccountRepository) + public CreateServiceAccountCommand( + IAccessPolicyRepository accessPolicyRepository, + IOrganizationUserRepository organizationUserRepository, + IServiceAccountRepository serviceAccountRepository) { + _accessPolicyRepository = accessPolicyRepository; + _organizationUserRepository = organizationUserRepository; _serviceAccountRepository = serviceAccountRepository; } - public async Task CreateAsync(ServiceAccount serviceAccount) + public async Task CreateAsync(ServiceAccount serviceAccount, Guid userId) { - return await _serviceAccountRepository.CreateAsync(serviceAccount); + var createdServiceAccount = await _serviceAccountRepository.CreateAsync(serviceAccount); + + var user = await _organizationUserRepository.GetByOrganizationAsync(createdServiceAccount.OrganizationId, + userId); + var accessPolicy = new UserServiceAccountAccessPolicy + { + OrganizationUserId = user.Id, + GrantedServiceAccountId = createdServiceAccount.Id, + Read = true, + Write = true, + }; + await _accessPolicyRepository.CreateManyAsync(new List { accessPolicy }); + return createdServiceAccount; } } diff --git a/bitwarden_license/src/Commercial.Core/SecretsManager/Commands/ServiceAccounts/UpdateServiceAccountCommand.cs b/bitwarden_license/src/Commercial.Core/SecretsManager/Commands/ServiceAccounts/UpdateServiceAccountCommand.cs index efc77fc040..378f3cbc33 100644 --- a/bitwarden_license/src/Commercial.Core/SecretsManager/Commands/ServiceAccounts/UpdateServiceAccountCommand.cs +++ b/bitwarden_license/src/Commercial.Core/SecretsManager/Commands/ServiceAccounts/UpdateServiceAccountCommand.cs @@ -26,6 +26,11 @@ public class UpdateServiceAccountCommand : IUpdateServiceAccountCommand throw new NotFoundException(); } + if (!_currentContext.AccessSecretsManager(serviceAccount.OrganizationId)) + { + throw new NotFoundException(); + } + var orgAdmin = await _currentContext.OrganizationAdmin(serviceAccount.OrganizationId); var accessClient = AccessClientHelper.ToAccessClient(_currentContext.ClientType, orgAdmin); @@ -38,7 +43,7 @@ public class UpdateServiceAccountCommand : IUpdateServiceAccountCommand if (!hasAccess) { - throw new UnauthorizedAccessException(); + throw new NotFoundException(); } serviceAccount.Name = updatedServiceAccount.Name; diff --git a/bitwarden_license/src/Commercial.Infrastructure.EntityFramework/SecretsManager/Repositories/AccessPolicyRepository.cs b/bitwarden_license/src/Commercial.Infrastructure.EntityFramework/SecretsManager/Repositories/AccessPolicyRepository.cs index dd56e08fcd..1cf066190e 100644 --- a/bitwarden_license/src/Commercial.Infrastructure.EntityFramework/SecretsManager/Repositories/AccessPolicyRepository.cs +++ b/bitwarden_license/src/Commercial.Infrastructure.EntityFramework/SecretsManager/Repositories/AccessPolicyRepository.cs @@ -138,7 +138,7 @@ public class AccessPolicyRepository : BaseEntityFrameworkRepository, IAccessPoli } } - public async Task?> GetManyByProjectId(Guid id) + public async Task> GetManyByGrantedProjectIdAsync(Guid id) { using (var scope = ServiceScopeFactory.CreateScope()) { @@ -153,10 +153,25 @@ public class AccessPolicyRepository : BaseEntityFrameworkRepository, IAccessPoli .Include(ap => ((ServiceAccountProjectAccessPolicy)ap).ServiceAccount) .ToListAsync(); - return !entities.Any() ? null : entities.Select(MapToCore); + return entities.Select(MapToCore); } } + public async Task> GetManyByGrantedServiceAccountIdAsync(Guid id) + { + using var scope = ServiceScopeFactory.CreateScope(); + var dbContext = GetDatabaseContext(scope); + + var entities = await dbContext.AccessPolicies.Where(ap => + ((UserServiceAccountAccessPolicy)ap).GrantedServiceAccountId == id || + ((GroupServiceAccountAccessPolicy)ap).GrantedServiceAccountId == id) + .Include(ap => ((UserServiceAccountAccessPolicy)ap).OrganizationUser.User) + .Include(ap => ((GroupServiceAccountAccessPolicy)ap).Group) + .ToListAsync(); + + return entities.Select(MapToCore); + } + public async Task DeleteAsync(Guid id) { using (var scope = ServiceScopeFactory.CreateScope()) @@ -178,6 +193,8 @@ public class AccessPolicyRepository : BaseEntityFrameworkRepository, IAccessPoli UserProjectAccessPolicy ap => Mapper.Map(ap), GroupProjectAccessPolicy ap => Mapper.Map(ap), ServiceAccountProjectAccessPolicy ap => Mapper.Map(ap), + UserServiceAccountAccessPolicy ap => Mapper.Map(ap), + GroupServiceAccountAccessPolicy ap => Mapper.Map(ap), _ => throw new ArgumentException("Unsupported access policy type") }; } diff --git a/bitwarden_license/test/Commercial.Core.Test/SecretsManager/AccessTokens/CreateAccessTokenCommandTests.cs b/bitwarden_license/test/Commercial.Core.Test/SecretsManager/AccessTokens/CreateAccessTokenCommandTests.cs index d9b2027c36..de34e77392 100644 --- a/bitwarden_license/test/Commercial.Core.Test/SecretsManager/AccessTokens/CreateAccessTokenCommandTests.cs +++ b/bitwarden_license/test/Commercial.Core.Test/SecretsManager/AccessTokens/CreateAccessTokenCommandTests.cs @@ -36,7 +36,7 @@ public class CreateServiceAccountCommandTests sutProvider.GetDependency().GetByIdAsync(saData.Id).Returns(saData); sutProvider.GetDependency().UserHasWriteAccessToServiceAccount(saData.Id, userId).Returns(false); - await Assert.ThrowsAsync(() => sutProvider.Sut.CreateAsync(data, userId)); + await Assert.ThrowsAsync(() => sutProvider.Sut.CreateAsync(data, userId)); await sutProvider.GetDependency().DidNotReceiveWithAnyArgs().CreateAsync(default); } @@ -49,6 +49,7 @@ public class CreateServiceAccountCommandTests data.ServiceAccountId = saData.Id; sutProvider.GetDependency().GetByIdAsync(saData.Id).Returns(saData); sutProvider.GetDependency().UserHasWriteAccessToServiceAccount(saData.Id, userId).Returns(true); + sutProvider.GetDependency().AccessSecretsManager(saData.OrganizationId).Returns(true); await sutProvider.Sut.CreateAsync(data, userId); @@ -64,6 +65,7 @@ public class CreateServiceAccountCommandTests data.ServiceAccountId = saData.Id; sutProvider.GetDependency().GetByIdAsync(saData.Id).Returns(saData); + sutProvider.GetDependency().AccessSecretsManager(saData.OrganizationId).Returns(true); sutProvider.GetDependency().OrganizationAdmin(saData.OrganizationId).Returns(true); await sutProvider.Sut.CreateAsync(data, userId); diff --git a/bitwarden_license/test/Commercial.Core.Test/SecretsManager/Projects/DeleteProjectCommandTests.cs b/bitwarden_license/test/Commercial.Core.Test/SecretsManager/Projects/DeleteProjectCommandTests.cs index 3d93d39793..e48c2cf0af 100644 --- a/bitwarden_license/test/Commercial.Core.Test/SecretsManager/Projects/DeleteProjectCommandTests.cs +++ b/bitwarden_license/test/Commercial.Core.Test/SecretsManager/Projects/DeleteProjectCommandTests.cs @@ -28,7 +28,7 @@ public class DeleteProjectCommandTests [Theory] [BitAutoData] - public async Task DeleteSecrets_OneIdNotFound_Throws_NotFoundException(List data, Guid userId, + public async Task Delete_OneIdNotFound_Throws_NotFoundException(List data, Guid userId, SutProvider sutProvider) { var project = new Project() @@ -49,6 +49,7 @@ public class DeleteProjectCommandTests { var projects = data.Select(id => new Project { Id = id, OrganizationId = organizationId }).ToList(); + sutProvider.GetDependency().AccessSecretsManager(organizationId).Returns(true); sutProvider.GetDependency().ClientType = ClientType.User; sutProvider.GetDependency().GetManyByIds(data).Returns(projects); sutProvider.GetDependency().UserHasWriteAccessToProject(Arg.Any(), userId).Returns(true); @@ -65,11 +66,12 @@ public class DeleteProjectCommandTests [Theory] [BitAutoData] - public async Task DeleteSecrets_User_No_Permission(List data, Guid userId, Guid organizationId, + public async Task Delete_User_No_Permission(List data, Guid userId, Guid organizationId, SutProvider sutProvider) { var projects = data.Select(id => new Project { Id = id, OrganizationId = organizationId }).ToList(); + sutProvider.GetDependency().AccessSecretsManager(organizationId).Returns(true); sutProvider.GetDependency().ClientType = ClientType.User; sutProvider.GetDependency().GetManyByIds(data).Returns(projects); sutProvider.GetDependency().UserHasWriteAccessToProject(userId, userId).Returns(false); @@ -86,11 +88,12 @@ public class DeleteProjectCommandTests [Theory] [BitAutoData] - public async Task DeleteSecrets_OrganizationAdmin_Success(List data, Guid userId, Guid organizationId, + public async Task Delete_OrganizationAdmin_Success(List data, Guid userId, Guid organizationId, SutProvider sutProvider) { var projects = data.Select(id => new Project { Id = id, OrganizationId = organizationId }).ToList(); + sutProvider.GetDependency().AccessSecretsManager(organizationId).Returns(true); sutProvider.GetDependency().OrganizationAdmin(organizationId).Returns(true); sutProvider.GetDependency().GetManyByIds(data).Returns(projects); diff --git a/bitwarden_license/test/Commercial.Core.Test/SecretsManager/Projects/UpdateProjectCommandTests.cs b/bitwarden_license/test/Commercial.Core.Test/SecretsManager/Projects/UpdateProjectCommandTests.cs index d85a44a911..8bacf0fc20 100644 --- a/bitwarden_license/test/Commercial.Core.Test/SecretsManager/Projects/UpdateProjectCommandTests.cs +++ b/bitwarden_license/test/Commercial.Core.Test/SecretsManager/Projects/UpdateProjectCommandTests.cs @@ -33,6 +33,7 @@ public class UpdateProjectCommandTests public async Task UpdateAsync_Admin_Succeeds(Project project, Guid userId, SutProvider sutProvider) { sutProvider.GetDependency().GetByIdAsync(project.Id).Returns(project); + sutProvider.GetDependency().AccessSecretsManager(project.OrganizationId).Returns(true); sutProvider.GetDependency().OrganizationAdmin(project.OrganizationId).Returns(true); var project2 = new Project { Id = project.Id, Name = "newName" }; @@ -51,8 +52,9 @@ public class UpdateProjectCommandTests { sutProvider.GetDependency().GetByIdAsync(project.Id).Returns(project); sutProvider.GetDependency().UserHasWriteAccessToProject(project.Id, userId).Returns(false); + sutProvider.GetDependency().AccessSecretsManager(project.OrganizationId).Returns(true); - await Assert.ThrowsAsync(() => sutProvider.Sut.UpdateAsync(project, userId)); + await Assert.ThrowsAsync(() => sutProvider.Sut.UpdateAsync(project, userId)); await sutProvider.GetDependency().DidNotReceiveWithAnyArgs().ReplaceAsync(default); } @@ -63,6 +65,7 @@ public class UpdateProjectCommandTests { sutProvider.GetDependency().GetByIdAsync(project.Id).Returns(project); sutProvider.GetDependency().UserHasWriteAccessToProject(project.Id, userId).Returns(true); + sutProvider.GetDependency().AccessSecretsManager(project.OrganizationId).Returns(true); var project2 = new Project { Id = project.Id, Name = "newName" }; var result = await sutProvider.Sut.UpdateAsync(project2, userId); diff --git a/bitwarden_license/test/Commercial.Core.Test/SecretsManager/Secrets/DeleteSecretCommandTests.cs b/bitwarden_license/test/Commercial.Core.Test/SecretsManager/Secrets/DeleteSecretCommandTests.cs index d5adec8827..cee70548e7 100644 --- a/bitwarden_license/test/Commercial.Core.Test/SecretsManager/Secrets/DeleteSecretCommandTests.cs +++ b/bitwarden_license/test/Commercial.Core.Test/SecretsManager/Secrets/DeleteSecretCommandTests.cs @@ -1,4 +1,5 @@ using Bit.Commercial.Core.SecretsManager.Commands.Secrets; +using Bit.Core.Context; using Bit.Core.Exceptions; using Bit.Core.SecretsManager.Entities; using Bit.Core.SecretsManager.Repositories; @@ -56,6 +57,7 @@ public class DeleteSecretCommandTests } sutProvider.GetDependency().GetManyByIds(data).Returns(secrets); + sutProvider.GetDependency().AccessSecretsManager(default).ReturnsForAnyArgs(true); var results = await sutProvider.Sut.DeleteSecrets(data); diff --git a/bitwarden_license/test/Commercial.Core.Test/SecretsManager/ServiceAccounts/CreateServiceAccountCommandTests.cs b/bitwarden_license/test/Commercial.Core.Test/SecretsManager/ServiceAccounts/CreateServiceAccountCommandTests.cs index 3c3e11a6a0..7acd315651 100644 --- a/bitwarden_license/test/Commercial.Core.Test/SecretsManager/ServiceAccounts/CreateServiceAccountCommandTests.cs +++ b/bitwarden_license/test/Commercial.Core.Test/SecretsManager/ServiceAccounts/CreateServiceAccountCommandTests.cs @@ -1,4 +1,6 @@ using Bit.Commercial.Core.SecretsManager.Commands.ServiceAccounts; +using Bit.Core.Entities; +using Bit.Core.Repositories; using Bit.Core.SecretsManager.Entities; using Bit.Core.SecretsManager.Repositories; using Bit.Test.Common.AutoFixture; @@ -15,9 +17,18 @@ public class CreateServiceAccountCommandTests [Theory] [BitAutoData] public async Task CreateAsync_CallsCreate(ServiceAccount data, - SutProvider sutProvider) + Guid userId, + SutProvider sutProvider) { - await sutProvider.Sut.CreateAsync(data); + sutProvider.GetDependency() + .GetByOrganizationAsync(Arg.Any(), Arg.Any()) + .Returns(new OrganizationUser() { Id = userId }); + + sutProvider.GetDependency() + .CreateAsync(Arg.Any()) + .Returns(data); + + await sutProvider.Sut.CreateAsync(data, userId); await sutProvider.GetDependency().Received(1) .CreateAsync(Arg.Is(AssertHelper.AssertPropertyEqual(data))); diff --git a/bitwarden_license/test/Commercial.Core.Test/SecretsManager/ServiceAccounts/UpdateServiceAccountCommandTests.cs b/bitwarden_license/test/Commercial.Core.Test/SecretsManager/ServiceAccounts/UpdateServiceAccountCommandTests.cs index 0b75cb2a9a..3a06eac474 100644 --- a/bitwarden_license/test/Commercial.Core.Test/SecretsManager/ServiceAccounts/UpdateServiceAccountCommandTests.cs +++ b/bitwarden_license/test/Commercial.Core.Test/SecretsManager/ServiceAccounts/UpdateServiceAccountCommandTests.cs @@ -18,7 +18,7 @@ public class UpdateServiceAccountCommandTests [BitAutoData] public async Task UpdateAsync_ServiceAccountDoesNotExist_ThrowsNotFound(ServiceAccount data, Guid userId, SutProvider sutProvider) { - var exception = await Assert.ThrowsAsync(() => sutProvider.Sut.UpdateAsync(data, userId)); + await Assert.ThrowsAsync(() => sutProvider.Sut.UpdateAsync(data, userId)); await sutProvider.GetDependency().DidNotReceiveWithAnyArgs().ReplaceAsync(default); } @@ -30,7 +30,7 @@ public class UpdateServiceAccountCommandTests sutProvider.GetDependency().GetByIdAsync(data.Id).Returns(data); sutProvider.GetDependency().UserHasWriteAccessToServiceAccount(data.Id, userId).Returns(false); - await Assert.ThrowsAsync(() => sutProvider.Sut.UpdateAsync(data, userId)); + await Assert.ThrowsAsync(() => sutProvider.Sut.UpdateAsync(data, userId)); await sutProvider.GetDependency().DidNotReceiveWithAnyArgs().ReplaceAsync(default); } @@ -39,6 +39,7 @@ public class UpdateServiceAccountCommandTests [BitAutoData] public async Task UpdateAsync_User_Success(ServiceAccount data, Guid userId, SutProvider sutProvider) { + sutProvider.GetDependency().AccessSecretsManager(data.OrganizationId).Returns(true); sutProvider.GetDependency().GetByIdAsync(data.Id).Returns(data); sutProvider.GetDependency().UserHasWriteAccessToServiceAccount(data.Id, userId).Returns(true); @@ -54,6 +55,7 @@ public class UpdateServiceAccountCommandTests public async Task UpdateAsync_Admin_Success(ServiceAccount data, Guid userId, SutProvider sutProvider) { sutProvider.GetDependency().GetByIdAsync(data.Id).Returns(data); + sutProvider.GetDependency().AccessSecretsManager(data.OrganizationId).Returns(true); sutProvider.GetDependency().OrganizationAdmin(data.OrganizationId).Returns(true); await sutProvider.Sut.UpdateAsync(data, userId); @@ -66,6 +68,7 @@ public class UpdateServiceAccountCommandTests [BitAutoData] public async Task UpdateAsync_DoesNotModifyOrganizationId(ServiceAccount existingServiceAccount, Guid userId, SutProvider sutProvider) { + sutProvider.GetDependency().AccessSecretsManager(existingServiceAccount.OrganizationId).Returns(true); sutProvider.GetDependency().GetByIdAsync(existingServiceAccount.Id).Returns(existingServiceAccount); sutProvider.GetDependency().UserHasWriteAccessToServiceAccount(existingServiceAccount.Id, userId).Returns(true); @@ -87,6 +90,7 @@ public class UpdateServiceAccountCommandTests [BitAutoData] public async Task UpdateAsync_DoesNotModifyCreationDate(ServiceAccount existingServiceAccount, Guid userId, SutProvider sutProvider) { + sutProvider.GetDependency().AccessSecretsManager(existingServiceAccount.OrganizationId).Returns(true); sutProvider.GetDependency().GetByIdAsync(existingServiceAccount.Id).Returns(existingServiceAccount); sutProvider.GetDependency().UserHasWriteAccessToServiceAccount(existingServiceAccount.Id, userId).Returns(true); @@ -108,6 +112,7 @@ public class UpdateServiceAccountCommandTests [BitAutoData] public async Task UpdateAsync_RevisionDateIsUpdatedToUtcNow(ServiceAccount existingServiceAccount, Guid userId, SutProvider sutProvider) { + sutProvider.GetDependency().AccessSecretsManager(existingServiceAccount.OrganizationId).Returns(true); sutProvider.GetDependency().GetByIdAsync(existingServiceAccount.Id).Returns(existingServiceAccount); sutProvider.GetDependency().UserHasWriteAccessToServiceAccount(existingServiceAccount.Id, userId).Returns(true); diff --git a/dev/migrate.ps1 b/dev/migrate.ps1 index 4c878a5d10..c1894342b9 100755 --- a/dev/migrate.ps1 +++ b/dev/migrate.ps1 @@ -6,7 +6,15 @@ # in the future and investigate if we can migrate back. # docker-compose --profile mssql exec mssql bash /mnt/helpers/run_migrations.sh @args -param([switch]$all = $false, [switch]$postgres = $false, [switch]$mysql = $false, [switch]$mssql = $false, [switch]$sqlite = $false) +param( + [switch]$all = $false, + [switch]$postgres = $false, + [switch]$mysql = $false, + [switch]$mssql = $false, + [switch]$sqlite = $false, + [switch]$selfhost = $false, + [switch]$pipeline = $false +) if (!$all -and !$postgres -and !$mysql -and !$sqlite) { $mssql = $true; @@ -21,6 +29,12 @@ if ($all -or $postgres -or $mysql -or $sqlite) { } if ($all -or $mssql) { + if ($selfhost) { + $migrationArgs = "-s" + } elseif ($pipeline) { + $migrationArgs = "-p" + } + Write-Host "Starting Microsoft SQL Server Migrations" docker run ` -v "$(pwd)/helpers/mssql:/mnt/helpers" ` @@ -30,7 +44,7 @@ if ($all -or $mssql) { --network=bitwardenserver_default ` --rm ` mcr.microsoft.com/mssql-tools ` - /mnt/helpers/run_migrations.sh @args + /mnt/helpers/run_migrations.sh $migrationArgs } $currentDir = Get-Location diff --git a/docker-unified/Dockerfile b/docker-unified/Dockerfile index 0814ec9f05..110ca7991b 100644 --- a/docker-unified/Dockerfile +++ b/docker-unified/Dockerfile @@ -227,6 +227,7 @@ RUN mkdir -p /var/log/bitwarden RUN mkdir -p /var/log/nginx/logs RUN mkdir -p /etc/nginx/http.d RUN mkdir -p /var/run/nginx +RUN mkdir -p /var/lib/nginx/tmp RUN touch /var/run/nginx/nginx.pid RUN mkdir -p /app diff --git a/docker-unified/hbs/nginx-config.hbs b/docker-unified/hbs/nginx-config.hbs index d405bf5ac9..5b57673f1c 100644 --- a/docker-unified/hbs/nginx-config.hbs +++ b/docker-unified/hbs/nginx-config.hbs @@ -57,7 +57,7 @@ server { include /etc/nginx/security-headers-ssl.conf; {{/if}} include /etc/nginx/security-headers.conf; - add_header Content-Security-Policy "{{{String.Coalesce env.BW_CSP "default-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https://haveibeenpwned.com; child-src 'self' https://*.duosecurity.com https://*.duofederal.com; frame-src 'self' https://*.duosecurity.com https://*.duofederal.com; connect-src 'self' https://api.pwnedpasswords.com https://api.2fa.directory; object-src 'self' blob:;"}}}"; + add_header Content-Security-Policy "{{{String.Coalesce env.BW_CSP "default-src 'self'; script-src 'self' 'wasm-unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https://haveibeenpwned.com; child-src 'self' https://*.duosecurity.com https://*.duofederal.com; frame-src 'self' https://*.duosecurity.com https://*.duofederal.com; connect-src 'self' https://api.pwnedpasswords.com https://api.2fa.directory; object-src 'self' blob:;"}}}"; add_header X-Frame-Options SAMEORIGIN; add_header X-Robots-Tag "noindex, nofollow"; } @@ -101,7 +101,7 @@ server { root /app/Web; } - location /attachments { + location /attachments/ { alias /etc/bitwarden/attachments/; } {{#if (String.Equal env.BW_ENABLE_API "true")}} diff --git a/src/Admin/Controllers/ToolsController.cs b/src/Admin/Controllers/ToolsController.cs index 9bd6189b3e..b18864d371 100644 --- a/src/Admin/Controllers/ToolsController.cs +++ b/src/Admin/Controllers/ToolsController.cs @@ -3,6 +3,7 @@ using System.Text.Json; using Bit.Admin.Models; using Bit.Core.Entities; using Bit.Core.Models.BitStripe; +using Bit.Core.OrganizationFeatures.OrganizationLicenses.Interfaces; using Bit.Core.Repositories; using Bit.Core.Services; using Bit.Core.Settings; @@ -18,7 +19,7 @@ public class ToolsController : Controller { private readonly GlobalSettings _globalSettings; private readonly IOrganizationRepository _organizationRepository; - private readonly IOrganizationService _organizationService; + private readonly ICloudGetOrganizationLicenseQuery _cloudGetOrganizationLicenseQuery; private readonly IUserService _userService; private readonly ITransactionRepository _transactionRepository; private readonly IInstallationRepository _installationRepository; @@ -30,7 +31,7 @@ public class ToolsController : Controller public ToolsController( GlobalSettings globalSettings, IOrganizationRepository organizationRepository, - IOrganizationService organizationService, + ICloudGetOrganizationLicenseQuery cloudGetOrganizationLicenseQuery, IUserService userService, ITransactionRepository transactionRepository, IInstallationRepository installationRepository, @@ -41,7 +42,7 @@ public class ToolsController : Controller { _globalSettings = globalSettings; _organizationRepository = organizationRepository; - _organizationService = organizationService; + _cloudGetOrganizationLicenseQuery = cloudGetOrganizationLicenseQuery; _userService = userService; _transactionRepository = transactionRepository; _installationRepository = installationRepository; @@ -259,7 +260,7 @@ public class ToolsController : Controller if (organization != null) { - var license = await _organizationService.GenerateLicenseAsync(organization, + var license = await _cloudGetOrganizationLicenseQuery.GetLicenseAsync(organization, model.InstallationId.Value, model.Version); var ms = new MemoryStream(); await JsonSerializer.SerializeAsync(ms, license, JsonHelpers.Indented); diff --git a/src/Api/Controllers/LicensesController.cs b/src/Api/Controllers/LicensesController.cs index 63ed824795..f5391fddc2 100644 --- a/src/Api/Controllers/LicensesController.cs +++ b/src/Api/Controllers/LicensesController.cs @@ -1,6 +1,9 @@ using Bit.Core.Context; using Bit.Core.Exceptions; +using Bit.Core.Models.Api.OrganizationLicenses; using Bit.Core.Models.Business; +using Bit.Core.OrganizationFeatures.OrganizationConnections.Interfaces; +using Bit.Core.OrganizationFeatures.OrganizationLicenses.Interfaces; using Bit.Core.Repositories; using Bit.Core.Services; using Bit.Core.Utilities; @@ -14,26 +17,26 @@ namespace Bit.Api.Controllers; [SelfHosted(NotSelfHostedOnly = true)] public class LicensesController : Controller { - private readonly ILicensingService _licensingService; private readonly IUserRepository _userRepository; private readonly IUserService _userService; private readonly IOrganizationRepository _organizationRepository; - private readonly IOrganizationService _organizationService; + private readonly ICloudGetOrganizationLicenseQuery _cloudGetOrganizationLicenseQuery; + private readonly IValidateBillingSyncKeyCommand _validateBillingSyncKeyCommand; private readonly ICurrentContext _currentContext; public LicensesController( - ILicensingService licensingService, IUserRepository userRepository, IUserService userService, IOrganizationRepository organizationRepository, - IOrganizationService organizationService, + ICloudGetOrganizationLicenseQuery cloudGetOrganizationLicenseQuery, + IValidateBillingSyncKeyCommand validateBillingSyncKeyCommand, ICurrentContext currentContext) { - _licensingService = licensingService; _userRepository = userRepository; _userService = userService; _organizationRepository = organizationRepository; - _organizationService = organizationService; + _cloudGetOrganizationLicenseQuery = cloudGetOrganizationLicenseQuery; + _validateBillingSyncKeyCommand = validateBillingSyncKeyCommand; _currentContext = currentContext; } @@ -55,21 +58,30 @@ public class LicensesController : Controller return license; } + /// + /// Used by self-hosted installations to get an updated license file + /// [HttpGet("organization/{id}")] - public async Task GetOrganization(string id, [FromQuery] string key) + public async Task OrganizationSync(string id, [FromBody] SelfHostedOrganizationLicenseRequestModel model) { - var org = await _organizationRepository.GetByIdAsync(new Guid(id)); - if (org == null) + var organization = await _organizationRepository.GetByIdAsync(new Guid(id)); + if (organization == null) { - return null; + throw new NotFoundException("Organization not found."); } - else if (!org.LicenseKey.Equals(key)) + + if (!organization.LicenseKey.Equals(model.LicenseKey)) { await Task.Delay(2000); throw new BadRequestException("Invalid license key."); } - var license = await _organizationService.GenerateLicenseAsync(org, _currentContext.InstallationId.Value); + if (!await _validateBillingSyncKeyCommand.ValidateBillingSyncKeyAsync(organization, model.BillingSyncKey)) + { + throw new BadRequestException("Invalid Billing Sync Key"); + } + + var license = await _cloudGetOrganizationLicenseQuery.GetLicenseAsync(organization, _currentContext.InstallationId.Value); return license; } } diff --git a/src/Api/Controllers/OrganizationConnectionsController.cs b/src/Api/Controllers/OrganizationConnectionsController.cs index 13260b7cca..b7329a14fa 100644 --- a/src/Api/Controllers/OrganizationConnectionsController.cs +++ b/src/Api/Controllers/OrganizationConnectionsController.cs @@ -191,7 +191,7 @@ public class OrganizationConnectionsController : Controller Guid? organizationConnectionId, OrganizationConnectionRequestModel model, Func, Task> validateAction = null) - where T : new() + where T : IConnectionConfig { var typedModel = new OrganizationConnectionRequestModel(model); if (validateAction != null) diff --git a/src/Api/Controllers/OrganizationSponsorshipsController.cs b/src/Api/Controllers/OrganizationSponsorshipsController.cs index fc5d38db1c..d9715d07c3 100644 --- a/src/Api/Controllers/OrganizationSponsorshipsController.cs +++ b/src/Api/Controllers/OrganizationSponsorshipsController.cs @@ -5,6 +5,7 @@ using Bit.Core.Entities; using Bit.Core.Exceptions; using Bit.Core.Models.Api.Request.OrganizationSponsorships; using Bit.Core.Models.Api.Response.OrganizationSponsorships; +using Bit.Core.OrganizationFeatures.OrganizationConnections.Interfaces; using Bit.Core.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterprise.Interfaces; using Bit.Core.Repositories; using Bit.Core.Services; diff --git a/src/Api/Controllers/OrganizationsController.cs b/src/Api/Controllers/OrganizationsController.cs index bb7c3a63a2..baf0dbfaaf 100644 --- a/src/Api/Controllers/OrganizationsController.cs +++ b/src/Api/Controllers/OrganizationsController.cs @@ -11,6 +11,7 @@ using Bit.Core.Exceptions; using Bit.Core.Models.Business; using Bit.Core.Models.Data.Organizations.Policies; using Bit.Core.OrganizationFeatures.OrganizationApiKeys.Interfaces; +using Bit.Core.OrganizationFeatures.OrganizationLicenses.Interfaces; using Bit.Core.Repositories; using Bit.Core.Services; using Bit.Core.Settings; @@ -37,6 +38,7 @@ public class OrganizationsController : Controller private readonly IRotateOrganizationApiKeyCommand _rotateOrganizationApiKeyCommand; private readonly ICreateOrganizationApiKeyCommand _createOrganizationApiKeyCommand; private readonly IOrganizationApiKeyRepository _organizationApiKeyRepository; + private readonly ICloudGetOrganizationLicenseQuery _cloudGetOrganizationLicenseQuery; private readonly GlobalSettings _globalSettings; public OrganizationsController( @@ -53,6 +55,7 @@ public class OrganizationsController : Controller IRotateOrganizationApiKeyCommand rotateOrganizationApiKeyCommand, ICreateOrganizationApiKeyCommand createOrganizationApiKeyCommand, IOrganizationApiKeyRepository organizationApiKeyRepository, + ICloudGetOrganizationLicenseQuery cloudGetOrganizationLicenseQuery, GlobalSettings globalSettings) { _organizationRepository = organizationRepository; @@ -68,6 +71,7 @@ public class OrganizationsController : Controller _rotateOrganizationApiKeyCommand = rotateOrganizationApiKeyCommand; _createOrganizationApiKeyCommand = createOrganizationApiKeyCommand; _organizationApiKeyRepository = organizationApiKeyRepository; + _cloudGetOrganizationLicenseQuery = cloudGetOrganizationLicenseQuery; _globalSettings = globalSettings; } @@ -149,7 +153,8 @@ public class OrganizationsController : Controller throw new NotFoundException(); } - var license = await _organizationService.GenerateLicenseAsync(orgIdGuid, installationId); + var org = await _organizationRepository.GetByIdAsync(new Guid(id)); + var license = await _cloudGetOrganizationLicenseQuery.GetLicenseAsync(org, installationId); if (license == null) { throw new NotFoundException(); @@ -215,6 +220,7 @@ public class OrganizationsController : Controller return new OrganizationResponseModel(result.Item1); } + [Obsolete("2022-12-7 Moved to SelfHostedOrganizationLicensesController, to be removed in EC-815")] [HttpPost("license")] [SelfHosted(SelfHostedOnly = true)] public async Task PostLicense(OrganizationCreateLicenseRequestModel model) @@ -448,6 +454,7 @@ public class OrganizationsController : Controller } } + [Obsolete("2022-12-7 Moved to SelfHostedOrganizationLicensesController, to be removed in EC-815")] [HttpPost("{id}/license")] [SelfHosted(SelfHostedOnly = true)] public async Task PostLicense(string id, LicenseRequestModel model) diff --git a/src/Api/Controllers/SelfHosted/SelfHostedOrganizationLicensesController.cs b/src/Api/Controllers/SelfHosted/SelfHostedOrganizationLicensesController.cs new file mode 100644 index 0000000000..92cf50ae41 --- /dev/null +++ b/src/Api/Controllers/SelfHosted/SelfHostedOrganizationLicensesController.cs @@ -0,0 +1,117 @@ +using Bit.Api.Models.Request; +using Bit.Api.Models.Request.Organizations; +using Bit.Api.Models.Response.Organizations; +using Bit.Api.Utilities; +using Bit.Core.Context; +using Bit.Core.Enums; +using Bit.Core.Exceptions; +using Bit.Core.Models.Business; +using Bit.Core.Models.OrganizationConnectionConfigs; +using Bit.Core.OrganizationFeatures.OrganizationLicenses.Interfaces; +using Bit.Core.Repositories; +using Bit.Core.Services; +using Bit.Core.Utilities; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace Bit.Api.Controllers.SelfHosted; + +[Route("organizations/licenses/self-hosted")] +[Authorize("Application")] +[SelfHosted(SelfHostedOnly = true)] +public class SelfHostedOrganizationLicensesController : Controller +{ + private readonly ICurrentContext _currentContext; + private readonly ISelfHostedGetOrganizationLicenseQuery _selfHostedGetOrganizationLicenseQuery; + private readonly IOrganizationConnectionRepository _organizationConnectionRepository; + private readonly IOrganizationService _organizationService; + private readonly IOrganizationRepository _organizationRepository; + private readonly IUserService _userService; + + public SelfHostedOrganizationLicensesController( + ICurrentContext currentContext, + ISelfHostedGetOrganizationLicenseQuery selfHostedGetOrganizationLicenseQuery, + IOrganizationConnectionRepository organizationConnectionRepository, + IOrganizationService organizationService, + IOrganizationRepository organizationRepository, + IUserService userService) + { + _currentContext = currentContext; + _selfHostedGetOrganizationLicenseQuery = selfHostedGetOrganizationLicenseQuery; + _organizationConnectionRepository = organizationConnectionRepository; + _organizationService = organizationService; + _organizationRepository = organizationRepository; + _userService = userService; + } + + [HttpPost("")] + public async Task PostLicenseAsync(OrganizationCreateLicenseRequestModel model) + { + var user = await _userService.GetUserByPrincipalAsync(User); + if (user == null) + { + throw new UnauthorizedAccessException(); + } + + var license = await ApiHelpers.ReadJsonFileFromBody(HttpContext, model.License); + if (license == null) + { + throw new BadRequestException("Invalid license"); + } + + var result = await _organizationService.SignUpAsync(license, user, model.Key, + model.CollectionName, model.Keys?.PublicKey, model.Keys?.EncryptedPrivateKey); + return new OrganizationResponseModel(result.Item1); + } + + [HttpPost("{id}")] + public async Task PostLicenseAsync(string id, LicenseRequestModel model) + { + var orgIdGuid = new Guid(id); + if (!await _currentContext.OrganizationOwner(orgIdGuid)) + { + throw new NotFoundException(); + } + + var license = await ApiHelpers.ReadJsonFileFromBody(HttpContext, model.License); + if (license == null) + { + throw new BadRequestException("Invalid license"); + } + + await _organizationService.UpdateLicenseAsync(new Guid(id), license); + } + + [HttpPost("{id}/sync")] + public async Task SyncLicenseAsync(string id) + { + var organization = await _organizationRepository.GetByIdAsync(new Guid(id)); + if (organization == null) + { + throw new NotFoundException(); + } + + if (!await _currentContext.OrganizationOwner(organization.Id)) + { + throw new NotFoundException(); + } + + var billingSyncConnection = + (await _organizationConnectionRepository.GetByOrganizationIdTypeAsync(organization.Id, + OrganizationConnectionType.CloudBillingSync)).FirstOrDefault(); + if (billingSyncConnection == null) + { + throw new NotFoundException("Unable to get Cloud Billing Sync connection"); + } + + var license = + await _selfHostedGetOrganizationLicenseQuery.GetLicenseAsync(organization, billingSyncConnection); + + await _organizationService.UpdateLicenseAsync(organization.Id, license); + + var config = billingSyncConnection.GetConfig(); + config.LastLicenseSync = DateTime.Now; + billingSyncConnection.SetConfig(config); + await _organizationConnectionRepository.ReplaceAsync(billingSyncConnection); + } +} diff --git a/src/Api/Models/Request/Organizations/OrganizationConnectionRequestModel.cs b/src/Api/Models/Request/Organizations/OrganizationConnectionRequestModel.cs index 9dbc9ca0a0..96a444c27a 100644 --- a/src/Api/Models/Request/Organizations/OrganizationConnectionRequestModel.cs +++ b/src/Api/Models/Request/Organizations/OrganizationConnectionRequestModel.cs @@ -2,6 +2,7 @@ using Bit.Core.Enums; using Bit.Core.Exceptions; using Bit.Core.Models.Data.Organizations.OrganizationConnections; +using Bit.Core.Models.OrganizationConnectionConfigs; using Bit.Core.Utilities; namespace Bit.Api.Models.Request.Organizations; @@ -17,7 +18,7 @@ public class OrganizationConnectionRequestModel } -public class OrganizationConnectionRequestModel : OrganizationConnectionRequestModel where T : new() +public class OrganizationConnectionRequestModel : OrganizationConnectionRequestModel where T : IConnectionConfig { public T ParsedConfig { get; private set; } diff --git a/src/Api/Models/Request/Organizations/OrganizationUserRequestModels.cs b/src/Api/Models/Request/Organizations/OrganizationUserRequestModels.cs index a09012d792..9a8ab0192c 100644 --- a/src/Api/Models/Request/Organizations/OrganizationUserRequestModels.cs +++ b/src/Api/Models/Request/Organizations/OrganizationUserRequestModels.cs @@ -17,6 +17,7 @@ public class OrganizationUserInviteRequestModel [Required] public OrganizationUserType? Type { get; set; } public bool AccessAll { get; set; } + public bool AccessSecretsManager { get; set; } public Permissions Permissions { get; set; } public IEnumerable Collections { get; set; } public IEnumerable Groups { get; set; } @@ -28,6 +29,7 @@ public class OrganizationUserInviteRequestModel Emails = Emails, Type = Type, AccessAll = AccessAll, + AccessSecretsManager = AccessSecretsManager, Collections = Collections?.Select(c => c.ToSelectionReadOnly()), Groups = Groups, Permissions = Permissions, @@ -73,6 +75,7 @@ public class OrganizationUserUpdateRequestModel [Required] public OrganizationUserType? Type { get; set; } public bool AccessAll { get; set; } + public bool AccessSecretsManager { get; set; } public Permissions Permissions { get; set; } public IEnumerable Collections { get; set; } public IEnumerable Groups { get; set; } @@ -85,6 +88,7 @@ public class OrganizationUserUpdateRequestModel PropertyNamingPolicy = JsonNamingPolicy.CamelCase, }); existingUser.AccessAll = AccessAll; + existingUser.AccessSecretsManager = AccessSecretsManager; return existingUser; } } diff --git a/src/Api/Models/Response/Organizations/OrganizationUserResponseModel.cs b/src/Api/Models/Response/Organizations/OrganizationUserResponseModel.cs index 6c83a76940..4c7424744c 100644 --- a/src/Api/Models/Response/Organizations/OrganizationUserResponseModel.cs +++ b/src/Api/Models/Response/Organizations/OrganizationUserResponseModel.cs @@ -23,6 +23,7 @@ public class OrganizationUserResponseModel : ResponseModel Type = organizationUser.Type; Status = organizationUser.Status; AccessAll = organizationUser.AccessAll; + AccessSecretsManager = organizationUser.AccessSecretsManager; Permissions = CoreHelpers.LoadClassFromJsonData(organizationUser.Permissions); ResetPasswordEnrolled = !string.IsNullOrEmpty(organizationUser.ResetPasswordKey); } @@ -40,6 +41,7 @@ public class OrganizationUserResponseModel : ResponseModel Type = organizationUser.Type; Status = organizationUser.Status; AccessAll = organizationUser.AccessAll; + AccessSecretsManager = organizationUser.AccessSecretsManager; Permissions = CoreHelpers.LoadClassFromJsonData(organizationUser.Permissions); ResetPasswordEnrolled = !string.IsNullOrEmpty(organizationUser.ResetPasswordKey); UsesKeyConnector = organizationUser.UsesKeyConnector; @@ -50,6 +52,7 @@ public class OrganizationUserResponseModel : ResponseModel public OrganizationUserType Type { get; set; } public OrganizationUserStatusType Status { get; set; } public bool AccessAll { get; set; } + public bool AccessSecretsManager { get; set; } public Permissions Permissions { get; set; } public bool ResetPasswordEnrolled { get; set; } public bool UsesKeyConnector { get; set; } diff --git a/src/Api/Models/Response/ProfileOrganizationResponseModel.cs b/src/Api/Models/Response/ProfileOrganizationResponseModel.cs index d2b98099ed..94ef68c263 100644 --- a/src/Api/Models/Response/ProfileOrganizationResponseModel.cs +++ b/src/Api/Models/Response/ProfileOrganizationResponseModel.cs @@ -52,6 +52,7 @@ public class ProfileOrganizationResponseModel : ResponseModel FamilySponsorshipLastSyncDate = organization.FamilySponsorshipLastSyncDate; FamilySponsorshipToDelete = organization.FamilySponsorshipToDelete; FamilySponsorshipValidUntil = organization.FamilySponsorshipValidUntil; + AccessSecretsManager = organization.AccessSecretsManager; if (organization.SsoConfig != null) { @@ -101,4 +102,5 @@ public class ProfileOrganizationResponseModel : ResponseModel public DateTime? FamilySponsorshipLastSyncDate { get; set; } public DateTime? FamilySponsorshipValidUntil { get; set; } public bool? FamilySponsorshipToDelete { get; set; } + public bool AccessSecretsManager { get; set; } } diff --git a/src/Api/Models/Response/ProfileProviderOrganizationResponseModel.cs b/src/Api/Models/Response/ProfileProviderOrganizationResponseModel.cs index 88c41d99c0..1d508cae17 100644 --- a/src/Api/Models/Response/ProfileProviderOrganizationResponseModel.cs +++ b/src/Api/Models/Response/ProfileProviderOrganizationResponseModel.cs @@ -1,5 +1,6 @@ using Bit.Core.Enums; using Bit.Core.Models.Data; +using Bit.Core.Utilities; namespace Bit.Api.Models.Response; @@ -39,5 +40,6 @@ public class ProfileProviderOrganizationResponseModel : ProfileOrganizationRespo UserId = organization.UserId?.ToString(); ProviderId = organization.ProviderId?.ToString(); ProviderName = organization.ProviderName; + PlanProductType = StaticStore.GetPlan(organization.PlanType).Product; } } diff --git a/src/Api/SecretsManager/Controllers/AccessPoliciesController.cs b/src/Api/SecretsManager/Controllers/AccessPoliciesController.cs index 493fbf5602..d2d3a4f28b 100644 --- a/src/Api/SecretsManager/Controllers/AccessPoliciesController.cs +++ b/src/Api/SecretsManager/Controllers/AccessPoliciesController.cs @@ -40,7 +40,7 @@ public class AccessPoliciesController : Controller [HttpGet("/projects/{id}/access-policies")] public async Task GetProjectAccessPoliciesAsync([FromRoute] Guid id) { - var results = await _accessPolicyRepository.GetManyByProjectId(id); + var results = await _accessPolicyRepository.GetManyByGrantedProjectIdAsync(id); return new ProjectAccessPoliciesResponseModel(results); } diff --git a/src/Api/SecretsManager/Controllers/ProjectsController.cs b/src/Api/SecretsManager/Controllers/ProjectsController.cs index d8ef5a00f7..437079d87d 100644 --- a/src/Api/SecretsManager/Controllers/ProjectsController.cs +++ b/src/Api/SecretsManager/Controllers/ProjectsController.cs @@ -7,61 +7,46 @@ using Bit.Core.Exceptions; using Bit.Core.SecretsManager.Commands.Projects.Interfaces; using Bit.Core.SecretsManager.Repositories; using Bit.Core.Services; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; namespace Bit.Api.SecretsManager.Controllers; [SecretsManager] +[Authorize("secrets")] public class ProjectsController : Controller { + private readonly ICurrentContext _currentContext; private readonly IUserService _userService; private readonly IProjectRepository _projectRepository; private readonly ICreateProjectCommand _createProjectCommand; private readonly IUpdateProjectCommand _updateProjectCommand; private readonly IDeleteProjectCommand _deleteProjectCommand; - private readonly ICurrentContext _currentContext; public ProjectsController( + ICurrentContext currentContext, IUserService userService, IProjectRepository projectRepository, ICreateProjectCommand createProjectCommand, IUpdateProjectCommand updateProjectCommand, - IDeleteProjectCommand deleteProjectCommand, - ICurrentContext currentContext) + IDeleteProjectCommand deleteProjectCommand) { + _currentContext = currentContext; _userService = userService; _projectRepository = projectRepository; _createProjectCommand = createProjectCommand; _updateProjectCommand = updateProjectCommand; _deleteProjectCommand = deleteProjectCommand; - _currentContext = currentContext; } - [HttpPost("organizations/{organizationId}/projects")] - public async Task CreateAsync([FromRoute] Guid organizationId, [FromBody] ProjectCreateRequestModel createRequest) + [HttpGet("organizations/{organizationId}/projects")] + public async Task> ListByOrganizationAsync([FromRoute] Guid organizationId) { - if (!await _currentContext.OrganizationUser(organizationId)) + if (!_currentContext.AccessSecretsManager(organizationId)) { throw new NotFoundException(); } - var result = await _createProjectCommand.CreateAsync(createRequest.ToProject(organizationId)); - return new ProjectResponseModel(result); - } - - [HttpPut("projects/{id}")] - public async Task UpdateProjectAsync([FromRoute] Guid id, [FromBody] ProjectUpdateRequestModel updateRequest) - { - var userId = _userService.GetProperUserId(User).Value; - - var result = await _updateProjectCommand.UpdateAsync(updateRequest.ToProject(id), userId); - return new ProjectResponseModel(result); - } - - [HttpGet("organizations/{organizationId}/projects")] - public async Task> GetProjectsByOrganizationAsync( - [FromRoute] Guid organizationId) - { var userId = _userService.GetProperUserId(User).Value; var orgAdmin = await _currentContext.OrganizationAdmin(organizationId); var accessClient = AccessClientHelper.ToAccessClient(_currentContext.ClientType, orgAdmin); @@ -72,8 +57,29 @@ public class ProjectsController : Controller return new ListResponseModel(responses); } + [HttpPost("organizations/{organizationId}/projects")] + public async Task CreateAsync([FromRoute] Guid organizationId, [FromBody] ProjectCreateRequestModel createRequest) + { + if (!_currentContext.AccessSecretsManager(organizationId)) + { + throw new NotFoundException(); + } + + var result = await _createProjectCommand.CreateAsync(createRequest.ToProject(organizationId)); + return new ProjectResponseModel(result); + } + + [HttpPut("projects/{id}")] + public async Task UpdateAsync([FromRoute] Guid id, [FromBody] ProjectUpdateRequestModel updateRequest) + { + var userId = _userService.GetProperUserId(User).Value; + + var result = await _updateProjectCommand.UpdateAsync(updateRequest.ToProject(id), userId); + return new ProjectResponseModel(result); + } + [HttpGet("projects/{id}")] - public async Task GetProjectAsync([FromRoute] Guid id) + public async Task GetAsync([FromRoute] Guid id) { var project = await _projectRepository.GetByIdAsync(id); if (project == null) @@ -81,6 +87,11 @@ public class ProjectsController : Controller throw new NotFoundException(); } + if (!_currentContext.AccessSecretsManager(project.OrganizationId)) + { + throw new NotFoundException(); + } + var userId = _userService.GetProperUserId(User).Value; var orgAdmin = await _currentContext.OrganizationAdmin(project.OrganizationId); var accessClient = AccessClientHelper.ToAccessClient(_currentContext.ClientType, orgAdmin); @@ -101,7 +112,7 @@ public class ProjectsController : Controller } [HttpPost("projects/delete")] - public async Task> BulkDeleteProjectsAsync([FromBody] List ids) + public async Task> BulkDeleteAsync([FromBody] List ids) { var userId = _userService.GetProperUserId(User).Value; diff --git a/src/Api/SecretsManager/Controllers/SecretsController.cs b/src/Api/SecretsManager/Controllers/SecretsController.cs index a66680f63b..3ddf4699d7 100644 --- a/src/Api/SecretsManager/Controllers/SecretsController.cs +++ b/src/Api/SecretsManager/Controllers/SecretsController.cs @@ -1,6 +1,7 @@ using Bit.Api.Models.Response; using Bit.Api.SecretsManager.Models.Request; using Bit.Api.SecretsManager.Models.Response; +using Bit.Core.Context; using Bit.Core.Exceptions; using Bit.Core.SecretsManager.Commands.Secrets.Interfaces; using Bit.Core.SecretsManager.Repositories; @@ -13,30 +14,52 @@ namespace Bit.Api.SecretsManager.Controllers; [Authorize("secrets")] public class SecretsController : Controller { + private readonly ICurrentContext _currentContext; private readonly ISecretRepository _secretRepository; - private readonly IProjectRepository _projectRepository; private readonly ICreateSecretCommand _createSecretCommand; private readonly IUpdateSecretCommand _updateSecretCommand; private readonly IDeleteSecretCommand _deleteSecretCommand; - public SecretsController(ISecretRepository secretRepository, IProjectRepository projectRepository, ICreateSecretCommand createSecretCommand, IUpdateSecretCommand updateSecretCommand, IDeleteSecretCommand deleteSecretCommand) + public SecretsController( + ICurrentContext currentContext, + ISecretRepository secretRepository, + ICreateSecretCommand createSecretCommand, + IUpdateSecretCommand updateSecretCommand, + IDeleteSecretCommand deleteSecretCommand) { + _currentContext = currentContext; _secretRepository = secretRepository; - _projectRepository = projectRepository; _createSecretCommand = createSecretCommand; _updateSecretCommand = updateSecretCommand; _deleteSecretCommand = deleteSecretCommand; } [HttpGet("organizations/{organizationId}/secrets")] - public async Task GetSecretsByOrganizationAsync([FromRoute] Guid organizationId) + public async Task ListByOrganizationAsync([FromRoute] Guid organizationId) { + if (!_currentContext.AccessSecretsManager(organizationId)) + { + throw new NotFoundException(); + } + var secrets = await _secretRepository.GetManyByOrganizationIdAsync(organizationId); return new SecretWithProjectsListResponseModel(secrets); } + [HttpPost("organizations/{organizationId}/secrets")] + public async Task CreateAsync([FromRoute] Guid organizationId, [FromBody] SecretCreateRequestModel createRequest) + { + if (!_currentContext.AccessSecretsManager(organizationId)) + { + throw new NotFoundException(); + } + + var result = await _createSecretCommand.CreateAsync(createRequest.ToSecret(organizationId)); + return new SecretResponseModel(result); + } + [HttpGet("secrets/{id}")] - public async Task GetSecretAsync([FromRoute] Guid id) + public async Task GetAsync([FromRoute] Guid id) { var secret = await _secretRepository.GetByIdAsync(id); if (secret == null) @@ -54,15 +77,8 @@ public class SecretsController : Controller return new SecretWithProjectsListResponseModel(secrets); } - [HttpPost("organizations/{organizationId}/secrets")] - public async Task CreateSecretAsync([FromRoute] Guid organizationId, [FromBody] SecretCreateRequestModel createRequest) - { - var result = await _createSecretCommand.CreateAsync(createRequest.ToSecret(organizationId)); - return new SecretResponseModel(result); - } - [HttpPut("secrets/{id}")] - public async Task UpdateSecretAsync([FromRoute] Guid id, [FromBody] SecretUpdateRequestModel updateRequest) + public async Task UpdateAsync([FromRoute] Guid id, [FromBody] SecretUpdateRequestModel updateRequest) { var result = await _updateSecretCommand.UpdateAsync(updateRequest.ToSecret(id)); return new SecretResponseModel(result); diff --git a/src/Api/SecretsManager/Controllers/ServiceAccountsController.cs b/src/Api/SecretsManager/Controllers/ServiceAccountsController.cs index 6456fa21e3..175db2a1f2 100644 --- a/src/Api/SecretsManager/Controllers/ServiceAccountsController.cs +++ b/src/Api/SecretsManager/Controllers/ServiceAccountsController.cs @@ -8,43 +8,50 @@ using Bit.Core.SecretsManager.Commands.AccessTokens.Interfaces; using Bit.Core.SecretsManager.Commands.ServiceAccounts.Interfaces; using Bit.Core.SecretsManager.Repositories; using Bit.Core.Services; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; namespace Bit.Api.SecretsManager.Controllers; [SecretsManager] +[Authorize("secrets")] [Route("service-accounts")] public class ServiceAccountsController : Controller { + private readonly ICurrentContext _currentContext; private readonly IApiKeyRepository _apiKeyRepository; private readonly ICreateAccessTokenCommand _createAccessTokenCommand; private readonly ICreateServiceAccountCommand _createServiceAccountCommand; - private readonly ICurrentContext _currentContext; private readonly IServiceAccountRepository _serviceAccountRepository; private readonly IUpdateServiceAccountCommand _updateServiceAccountCommand; private readonly IUserService _userService; public ServiceAccountsController( + ICurrentContext currentContext, IUserService userService, IServiceAccountRepository serviceAccountRepository, ICreateAccessTokenCommand createAccessTokenCommand, IApiKeyRepository apiKeyRepository, ICreateServiceAccountCommand createServiceAccountCommand, - IUpdateServiceAccountCommand updateServiceAccountCommand, - ICurrentContext currentContext) + IUpdateServiceAccountCommand updateServiceAccountCommand) { + _currentContext = currentContext; _userService = userService; _serviceAccountRepository = serviceAccountRepository; _apiKeyRepository = apiKeyRepository; _createServiceAccountCommand = createServiceAccountCommand; _updateServiceAccountCommand = updateServiceAccountCommand; _createAccessTokenCommand = createAccessTokenCommand; - _currentContext = currentContext; } [HttpGet("/organizations/{organizationId}/service-accounts")] - public async Task> GetServiceAccountsByOrganizationAsync( + public async Task> ListByOrganizationAsync( [FromRoute] Guid organizationId) { + if (!_currentContext.AccessSecretsManager(organizationId)) + { + throw new NotFoundException(); + } + var userId = _userService.GetProperUserId(User).Value; var orgAdmin = await _currentContext.OrganizationAdmin(organizationId); var accessClient = AccessClientHelper.ToAccessClient(_currentContext.ClientType, orgAdmin); @@ -57,20 +64,20 @@ public class ServiceAccountsController : Controller } [HttpPost("/organizations/{organizationId}/service-accounts")] - public async Task CreateServiceAccountAsync([FromRoute] Guid organizationId, + public async Task CreateAsync([FromRoute] Guid organizationId, [FromBody] ServiceAccountCreateRequestModel createRequest) { - if (!await _currentContext.OrganizationUser(organizationId)) + if (!_currentContext.AccessSecretsManager(organizationId)) { throw new NotFoundException(); } - - var result = await _createServiceAccountCommand.CreateAsync(createRequest.ToServiceAccount(organizationId)); + var userId = _userService.GetProperUserId(User).Value; + var result = await _createServiceAccountCommand.CreateAsync(createRequest.ToServiceAccount(organizationId), userId); return new ServiceAccountResponseModel(result); } [HttpPut("{id}")] - public async Task UpdateServiceAccountAsync([FromRoute] Guid id, + public async Task UpdateAsync([FromRoute] Guid id, [FromBody] ServiceAccountUpdateRequestModel updateRequest) { var userId = _userService.GetProperUserId(User).Value; @@ -89,6 +96,11 @@ public class ServiceAccountsController : Controller throw new NotFoundException(); } + if (!_currentContext.AccessSecretsManager(serviceAccount.OrganizationId)) + { + throw new NotFoundException(); + } + var orgAdmin = await _currentContext.OrganizationAdmin(serviceAccount.OrganizationId); var accessClient = AccessClientHelper.ToAccessClient(_currentContext.ClientType, orgAdmin); diff --git a/src/Api/SecretsManager/Models/Response/ProjectAccessPoliciesResponseModel.cs b/src/Api/SecretsManager/Models/Response/ProjectAccessPoliciesResponseModel.cs index c7170e1367..f03411cd39 100644 --- a/src/Api/SecretsManager/Models/Response/ProjectAccessPoliciesResponseModel.cs +++ b/src/Api/SecretsManager/Models/Response/ProjectAccessPoliciesResponseModel.cs @@ -10,11 +10,6 @@ public class ProjectAccessPoliciesResponseModel : ResponseModel public ProjectAccessPoliciesResponseModel(IEnumerable baseAccessPolicies) : base(_objectName) { - if (baseAccessPolicies == null) - { - return; - } - foreach (var baseAccessPolicy in baseAccessPolicies) switch (baseAccessPolicy) { diff --git a/src/Billing/Startup.cs b/src/Billing/Startup.cs index 2ad7d0ce7e..caf2235698 100644 --- a/src/Billing/Startup.cs +++ b/src/Billing/Startup.cs @@ -33,6 +33,9 @@ public class Startup StripeConfiguration.ApiKey = globalSettings.Stripe.ApiKey; StripeConfiguration.MaxNetworkRetries = globalSettings.Stripe.MaxNetworkRetries; + // Data Protection + services.AddCustomDataProtectionServices(Environment, globalSettings); + // Repositories services.AddDatabaseRepositories(globalSettings); diff --git a/src/Core/Context/CurrentContentOrganization.cs b/src/Core/Context/CurrentContentOrganization.cs index 040c1ece49..b21598a035 100644 --- a/src/Core/Context/CurrentContentOrganization.cs +++ b/src/Core/Context/CurrentContentOrganization.cs @@ -1,6 +1,6 @@ -using Bit.Core.Entities; -using Bit.Core.Enums; +using Bit.Core.Enums; using Bit.Core.Models.Data; +using Bit.Core.Models.Data.Organizations.OrganizationUsers; using Bit.Core.Utilities; namespace Bit.Core.Context; @@ -9,14 +9,16 @@ public class CurrentContentOrganization { public CurrentContentOrganization() { } - public CurrentContentOrganization(OrganizationUser orgUser) + public CurrentContentOrganization(OrganizationUserOrganizationDetails orgUser) { Id = orgUser.OrganizationId; Type = orgUser.Type; Permissions = CoreHelpers.LoadClassFromJsonData(orgUser.Permissions); + AccessSecretsManager = orgUser.AccessSecretsManager && orgUser.UseSecretsManager; } public Guid Id { get; set; } public OrganizationUserType Type { get; set; } public Permissions Permissions { get; set; } + public bool AccessSecretsManager { get; set; } } diff --git a/src/Core/Context/CurrentContext.cs b/src/Core/Context/CurrentContext.cs index 68e4246d04..4411509cd5 100644 --- a/src/Core/Context/CurrentContext.cs +++ b/src/Core/Context/CurrentContext.cs @@ -157,6 +157,10 @@ public class CurrentContext : ICurrentContext private List GetOrganizations(Dictionary> claimsDict, bool orgApi) { + var accessSecretsManager = claimsDict.ContainsKey(Claims.SecretsManagerAccess) + ? claimsDict[Claims.SecretsManagerAccess].ToDictionary(s => s.Value, _ => true) + : new Dictionary(); + var organizations = new List(); if (claimsDict.ContainsKey(Claims.OrganizationOwner)) { @@ -164,7 +168,8 @@ public class CurrentContext : ICurrentContext new CurrentContentOrganization { Id = new Guid(c.Value), - Type = OrganizationUserType.Owner + Type = OrganizationUserType.Owner, + AccessSecretsManager = accessSecretsManager.ContainsKey(c.Value), })); } else if (orgApi && OrganizationId.HasValue) @@ -172,7 +177,7 @@ public class CurrentContext : ICurrentContext organizations.Add(new CurrentContentOrganization { Id = OrganizationId.Value, - Type = OrganizationUserType.Owner + Type = OrganizationUserType.Owner, }); } @@ -182,7 +187,8 @@ public class CurrentContext : ICurrentContext new CurrentContentOrganization { Id = new Guid(c.Value), - Type = OrganizationUserType.Admin + Type = OrganizationUserType.Admin, + AccessSecretsManager = accessSecretsManager.ContainsKey(c.Value), })); } @@ -192,7 +198,8 @@ public class CurrentContext : ICurrentContext new CurrentContentOrganization { Id = new Guid(c.Value), - Type = OrganizationUserType.User + Type = OrganizationUserType.User, + AccessSecretsManager = accessSecretsManager.ContainsKey(c.Value), })); } @@ -202,7 +209,8 @@ public class CurrentContext : ICurrentContext new CurrentContentOrganization { Id = new Guid(c.Value), - Type = OrganizationUserType.Manager + Type = OrganizationUserType.Manager, + AccessSecretsManager = accessSecretsManager.ContainsKey(c.Value), })); } @@ -213,7 +221,8 @@ public class CurrentContext : ICurrentContext { Id = new Guid(c.Value), Type = OrganizationUserType.Custom, - Permissions = SetOrganizationPermissionsFromClaims(c.Value, claimsDict) + Permissions = SetOrganizationPermissionsFromClaims(c.Value, claimsDict), + AccessSecretsManager = accessSecretsManager.ContainsKey(c.Value), })); } @@ -434,12 +443,17 @@ public class CurrentContext : ICurrentContext return po?.ProviderId; } + public bool AccessSecretsManager(Guid orgId) + { + return Organizations?.Any(o => o.Id == orgId && o.AccessSecretsManager) ?? false; + } + public async Task> OrganizationMembershipAsync( IOrganizationUserRepository organizationUserRepository, Guid userId) { if (Organizations == null) { - var userOrgs = await organizationUserRepository.GetManyByUserAsync(userId); + var userOrgs = await organizationUserRepository.GetManyDetailsByUserAsync(userId); Organizations = userOrgs.Where(ou => ou.Status == OrganizationUserStatusType.Confirmed) .Select(ou => new CurrentContentOrganization(ou)).ToList(); } diff --git a/src/Core/Context/ICurrentContext.cs b/src/Core/Context/ICurrentContext.cs index d5ea350602..a78757d090 100644 --- a/src/Core/Context/ICurrentContext.cs +++ b/src/Core/Context/ICurrentContext.cs @@ -68,4 +68,5 @@ public interface ICurrentContext IProviderUserRepository providerUserRepository, Guid userId); Task ProviderIdForOrg(Guid orgId); + bool AccessSecretsManager(Guid organizationId); } diff --git a/src/Core/Entities/OrganizationConnection.cs b/src/Core/Entities/OrganizationConnection.cs index cc07177384..5b466fb4a6 100644 --- a/src/Core/Entities/OrganizationConnection.cs +++ b/src/Core/Entities/OrganizationConnection.cs @@ -1,15 +1,16 @@ using System.Text.Json; using Bit.Core.Enums; +using Bit.Core.Models.OrganizationConnectionConfigs; using Bit.Core.Utilities; namespace Bit.Core.Entities; -public class OrganizationConnection : OrganizationConnection where T : new() +public class OrganizationConnection : OrganizationConnection where T : IConnectionConfig { public new T Config { get => base.GetConfig(); - set => base.SetConfig(value); + set => base.SetConfig(value); } } @@ -26,7 +27,7 @@ public class OrganizationConnection : ITableObject Id = CoreHelpers.GenerateComb(); } - public T GetConfig() where T : new() + public T GetConfig() where T : IConnectionConfig { try { @@ -38,8 +39,32 @@ public class OrganizationConnection : ITableObject } } - public void SetConfig(T config) where T : new() + public void SetConfig(T config) where T : IConnectionConfig { Config = JsonSerializer.Serialize(config); } + + public bool Validate(out string exception) where T : IConnectionConfig + { + if (!Enabled) + { + exception = $"Connection disabled for organization {OrganizationId}"; + return false; + } + + if (string.IsNullOrWhiteSpace(Config)) + { + exception = $"No saved Connection config for organization {OrganizationId}"; + return false; + } + + var config = GetConfig(); + if (config == null) + { + exception = $"Error parsing Connection config for organization {OrganizationId}"; + return false; + } + + return config.Validate(out exception); + } } diff --git a/src/Core/Entities/OrganizationUser.cs b/src/Core/Entities/OrganizationUser.cs index ee1bdc15d4..9e2efb2626 100644 --- a/src/Core/Entities/OrganizationUser.cs +++ b/src/Core/Entities/OrganizationUser.cs @@ -22,6 +22,7 @@ public class OrganizationUser : ITableObject, IExternal public DateTime CreationDate { get; internal set; } = DateTime.UtcNow; public DateTime RevisionDate { get; internal set; } = DateTime.UtcNow; public string Permissions { get; set; } + public bool AccessSecretsManager { get; set; } public void SetNewId() { diff --git a/src/Core/Entities/User.cs b/src/Core/Entities/User.cs index 65af18c449..3b59729c14 100644 --- a/src/Core/Entities/User.cs +++ b/src/Core/Entities/User.cs @@ -65,6 +65,10 @@ public class User : ITableObject, ISubscriber, IStorable, IStorableSubscri public bool UnknownDeviceVerificationEnabled { get; set; } [MaxLength(7)] public string AvatarColor { get; set; } + public DateTime? LastPasswordChangeDate { get; set; } + public DateTime? LastKdfChangeDate { get; set; } + public DateTime? LastKeyRotationDate { get; set; } + public DateTime? LastEmailChangeDate { get; set; } public void SetNewId() { diff --git a/src/Core/Identity/Claims.cs b/src/Core/Identity/Claims.cs index b56b23ad86..318f0b4009 100644 --- a/src/Core/Identity/Claims.cs +++ b/src/Core/Identity/Claims.cs @@ -6,6 +6,7 @@ public static class Claims public const string SecurityStamp = "sstamp"; public const string Premium = "premium"; public const string Device = "device"; + public const string OrganizationOwner = "orgowner"; public const string OrganizationAdmin = "orgadmin"; public const string OrganizationManager = "orgmanager"; @@ -14,6 +15,8 @@ public static class Claims public const string ProviderAdmin = "providerprovideradmin"; public const string ProviderServiceUser = "providerserviceuser"; + public const string SecretsManagerAccess = "accesssecretsmanager"; + // Service Account public const string Organization = "organization"; diff --git a/src/Core/Models/Api/Request/OrganizationLicenses/SelfHostedOrganizationLicenseRequestModel.cs b/src/Core/Models/Api/Request/OrganizationLicenses/SelfHostedOrganizationLicenseRequestModel.cs new file mode 100644 index 0000000000..365d88877e --- /dev/null +++ b/src/Core/Models/Api/Request/OrganizationLicenses/SelfHostedOrganizationLicenseRequestModel.cs @@ -0,0 +1,7 @@ +namespace Bit.Core.Models.Api.OrganizationLicenses; + +public class SelfHostedOrganizationLicenseRequestModel +{ + public string LicenseKey { get; set; } + public string BillingSyncKey { get; set; } +} diff --git a/src/Core/Models/Business/OrganizationUserInvite.cs b/src/Core/Models/Business/OrganizationUserInvite.cs index 78edfb267e..7102a5f9ef 100644 --- a/src/Core/Models/Business/OrganizationUserInvite.cs +++ b/src/Core/Models/Business/OrganizationUserInvite.cs @@ -8,6 +8,7 @@ public class OrganizationUserInvite public IEnumerable Emails { get; set; } public Enums.OrganizationUserType? Type { get; set; } public bool AccessAll { get; set; } + public bool AccessSecretsManager { get; set; } public Permissions Permissions { get; set; } public IEnumerable Collections { get; set; } public IEnumerable Groups { get; set; } @@ -19,6 +20,7 @@ public class OrganizationUserInvite Emails = requestModel.Emails; Type = requestModel.Type; AccessAll = requestModel.AccessAll; + AccessSecretsManager = requestModel.AccessSecretsManager; Collections = requestModel.Collections; Groups = requestModel.Groups; Permissions = requestModel.Permissions; diff --git a/src/Core/Models/Data/Organizations/OrganizationConnections/OrganizationConnectionData.cs b/src/Core/Models/Data/Organizations/OrganizationConnections/OrganizationConnectionData.cs index 3a3edaed45..7a9aa77110 100644 --- a/src/Core/Models/Data/Organizations/OrganizationConnections/OrganizationConnectionData.cs +++ b/src/Core/Models/Data/Organizations/OrganizationConnections/OrganizationConnectionData.cs @@ -1,9 +1,10 @@ using Bit.Core.Entities; using Bit.Core.Enums; +using Bit.Core.Models.OrganizationConnectionConfigs; namespace Bit.Core.Models.Data.Organizations.OrganizationConnections; -public class OrganizationConnectionData where T : new() +public class OrganizationConnectionData where T : IConnectionConfig { public Guid? Id { get; set; } public OrganizationConnectionType Type { get; set; } diff --git a/src/Core/Models/Data/Organizations/OrganizationUsers/OrganizationUserInviteData.cs b/src/Core/Models/Data/Organizations/OrganizationUsers/OrganizationUserInviteData.cs index 887b64e963..f8789fe5d5 100644 --- a/src/Core/Models/Data/Organizations/OrganizationUsers/OrganizationUserInviteData.cs +++ b/src/Core/Models/Data/Organizations/OrganizationUsers/OrganizationUserInviteData.cs @@ -7,6 +7,7 @@ public class OrganizationUserInviteData public IEnumerable Emails { get; set; } public OrganizationUserType? Type { get; set; } public bool AccessAll { get; set; } + public bool AccessSecretsManager { get; set; } public IEnumerable Collections { get; set; } public IEnumerable Groups { get; set; } public Permissions Permissions { get; set; } diff --git a/src/Core/Models/Data/Organizations/OrganizationUsers/OrganizationUserOrganizationDetails.cs b/src/Core/Models/Data/Organizations/OrganizationUsers/OrganizationUserOrganizationDetails.cs index e104dd6213..32b7003700 100644 --- a/src/Core/Models/Data/Organizations/OrganizationUsers/OrganizationUserOrganizationDetails.cs +++ b/src/Core/Models/Data/Organizations/OrganizationUsers/OrganizationUserOrganizationDetails.cs @@ -41,4 +41,5 @@ public class OrganizationUserOrganizationDetails public DateTime? FamilySponsorshipLastSyncDate { get; set; } public DateTime? FamilySponsorshipValidUntil { get; set; } public bool? FamilySponsorshipToDelete { get; set; } + public bool AccessSecretsManager { get; set; } } diff --git a/src/Core/Models/Data/Organizations/OrganizationUsers/OrganizationUserUserDetails.cs b/src/Core/Models/Data/Organizations/OrganizationUsers/OrganizationUserUserDetails.cs index b155118161..74e06182bf 100644 --- a/src/Core/Models/Data/Organizations/OrganizationUsers/OrganizationUserUserDetails.cs +++ b/src/Core/Models/Data/Organizations/OrganizationUsers/OrganizationUserUserDetails.cs @@ -17,6 +17,7 @@ public class OrganizationUserUserDetails : IExternal, ITwoFactorProvidersUser public OrganizationUserStatusType Status { get; set; } public OrganizationUserType Type { get; set; } public bool AccessAll { get; set; } + public bool AccessSecretsManager { get; set; } public string ExternalId { get; set; } public string SsoExternalId { get; set; } public string Permissions { get; set; } diff --git a/src/Core/Models/Data/Provider/ProviderUserOrganizationDetails.cs b/src/Core/Models/Data/Provider/ProviderUserOrganizationDetails.cs index e121962e6a..2d06fc4296 100644 --- a/src/Core/Models/Data/Provider/ProviderUserOrganizationDetails.cs +++ b/src/Core/Models/Data/Provider/ProviderUserOrganizationDetails.cs @@ -34,4 +34,5 @@ public class ProviderUserOrganizationDetails public Guid? ProviderId { get; set; } public Guid? ProviderUserId { get; set; } public string ProviderName { get; set; } + public Enums.PlanType PlanType { get; set; } } diff --git a/src/Core/Models/OrganizationConnectionConfigs/BillingSyncConfig.cs b/src/Core/Models/OrganizationConnectionConfigs/BillingSyncConfig.cs index 204e165d05..07f07093d2 100644 --- a/src/Core/Models/OrganizationConnectionConfigs/BillingSyncConfig.cs +++ b/src/Core/Models/OrganizationConnectionConfigs/BillingSyncConfig.cs @@ -1,7 +1,20 @@ namespace Bit.Core.Models.OrganizationConnectionConfigs; -public class BillingSyncConfig +public class BillingSyncConfig : IConnectionConfig { public string BillingSyncKey { get; set; } public Guid CloudOrganizationId { get; set; } + public DateTime? LastLicenseSync { get; set; } + + public bool Validate(out string exception) + { + if (string.IsNullOrWhiteSpace(BillingSyncKey)) + { + exception = "Failed to get Billing Sync Key"; + return false; + } + + exception = ""; + return true; + } } diff --git a/src/Core/Models/OrganizationConnectionConfigs/IConnectionConfig.cs b/src/Core/Models/OrganizationConnectionConfigs/IConnectionConfig.cs new file mode 100644 index 0000000000..9b02c359e4 --- /dev/null +++ b/src/Core/Models/OrganizationConnectionConfigs/IConnectionConfig.cs @@ -0,0 +1,6 @@ +namespace Bit.Core.Models.OrganizationConnectionConfigs; + +public interface IConnectionConfig +{ + bool Validate(out string exception); +} diff --git a/src/Core/Models/OrganizationConnectionConfigs/ScimConfig.cs b/src/Core/Models/OrganizationConnectionConfigs/ScimConfig.cs index 63a1606cb2..8a4fcb4e8c 100644 --- a/src/Core/Models/OrganizationConnectionConfigs/ScimConfig.cs +++ b/src/Core/Models/OrganizationConnectionConfigs/ScimConfig.cs @@ -3,9 +3,21 @@ using Bit.Core.Enums; namespace Bit.Core.Models.OrganizationConnectionConfigs; -public class ScimConfig +public class ScimConfig : IConnectionConfig { public bool Enabled { get; set; } [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public ScimProviderType? ScimProvider { get; set; } + + public bool Validate(out string exception) + { + if (!Enabled) + { + exception = "Scim Config is disabled"; + return false; + } + + exception = ""; + return true; + } } diff --git a/src/Core/OrganizationFeatures/OrganizationConnections/CreateOrganizationConnectionCommand.cs b/src/Core/OrganizationFeatures/OrganizationConnections/CreateOrganizationConnectionCommand.cs index e3f308bc57..6c019001c0 100644 --- a/src/Core/OrganizationFeatures/OrganizationConnections/CreateOrganizationConnectionCommand.cs +++ b/src/Core/OrganizationFeatures/OrganizationConnections/CreateOrganizationConnectionCommand.cs @@ -1,5 +1,6 @@ using Bit.Core.Entities; using Bit.Core.Models.Data.Organizations.OrganizationConnections; +using Bit.Core.Models.OrganizationConnectionConfigs; using Bit.Core.OrganizationFeatures.OrganizationConnections.Interfaces; using Bit.Core.Repositories; @@ -14,7 +15,7 @@ public class CreateOrganizationConnectionCommand : ICreateOrganizationConnection _organizationConnectionRepository = organizationConnectionRepository; } - public async Task CreateAsync(OrganizationConnectionData connectionData) where T : new() + public async Task CreateAsync(OrganizationConnectionData connectionData) where T : IConnectionConfig { return await _organizationConnectionRepository.CreateAsync(connectionData.ToEntity()); } diff --git a/src/Core/OrganizationFeatures/OrganizationConnections/Interfaces/ICreateOrganizationConnectionCommand.cs b/src/Core/OrganizationFeatures/OrganizationConnections/Interfaces/ICreateOrganizationConnectionCommand.cs index b31920b10a..a97be09c3b 100644 --- a/src/Core/OrganizationFeatures/OrganizationConnections/Interfaces/ICreateOrganizationConnectionCommand.cs +++ b/src/Core/OrganizationFeatures/OrganizationConnections/Interfaces/ICreateOrganizationConnectionCommand.cs @@ -1,9 +1,10 @@ using Bit.Core.Entities; using Bit.Core.Models.Data.Organizations.OrganizationConnections; +using Bit.Core.Models.OrganizationConnectionConfigs; namespace Bit.Core.OrganizationFeatures.OrganizationConnections.Interfaces; public interface ICreateOrganizationConnectionCommand { - Task CreateAsync(OrganizationConnectionData connectionData) where T : new(); + Task CreateAsync(OrganizationConnectionData connectionData) where T : IConnectionConfig; } diff --git a/src/Core/OrganizationFeatures/OrganizationConnections/Interfaces/IUpdateOrganizationConnectionCommand.cs b/src/Core/OrganizationFeatures/OrganizationConnections/Interfaces/IUpdateOrganizationConnectionCommand.cs index 742e89c970..b245b89693 100644 --- a/src/Core/OrganizationFeatures/OrganizationConnections/Interfaces/IUpdateOrganizationConnectionCommand.cs +++ b/src/Core/OrganizationFeatures/OrganizationConnections/Interfaces/IUpdateOrganizationConnectionCommand.cs @@ -1,9 +1,10 @@ using Bit.Core.Entities; using Bit.Core.Models.Data.Organizations.OrganizationConnections; +using Bit.Core.Models.OrganizationConnectionConfigs; namespace Bit.Core.OrganizationFeatures.OrganizationConnections.Interfaces; public interface IUpdateOrganizationConnectionCommand { - Task UpdateAsync(OrganizationConnectionData connectionData) where T : new(); + Task UpdateAsync(OrganizationConnectionData connectionData) where T : IConnectionConfig; } diff --git a/src/Core/OrganizationFeatures/OrganizationSponsorships/FamiliesForEnterprise/Interfaces/IValidateBillingSyncKeyCommand.cs b/src/Core/OrganizationFeatures/OrganizationConnections/Interfaces/IValidateBillingSyncKeyCommand.cs similarity index 64% rename from src/Core/OrganizationFeatures/OrganizationSponsorships/FamiliesForEnterprise/Interfaces/IValidateBillingSyncKeyCommand.cs rename to src/Core/OrganizationFeatures/OrganizationConnections/Interfaces/IValidateBillingSyncKeyCommand.cs index 53e926903f..9fb979548a 100644 --- a/src/Core/OrganizationFeatures/OrganizationSponsorships/FamiliesForEnterprise/Interfaces/IValidateBillingSyncKeyCommand.cs +++ b/src/Core/OrganizationFeatures/OrganizationConnections/Interfaces/IValidateBillingSyncKeyCommand.cs @@ -1,6 +1,6 @@ using Bit.Core.Entities; -namespace Bit.Core.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterprise.Interfaces; +namespace Bit.Core.OrganizationFeatures.OrganizationConnections.Interfaces; public interface IValidateBillingSyncKeyCommand { diff --git a/src/Core/OrganizationFeatures/OrganizationConnections/UpdateOrganizationConnectionCommand.cs b/src/Core/OrganizationFeatures/OrganizationConnections/UpdateOrganizationConnectionCommand.cs index 0d872b6f1f..3e64fd47ab 100644 --- a/src/Core/OrganizationFeatures/OrganizationConnections/UpdateOrganizationConnectionCommand.cs +++ b/src/Core/OrganizationFeatures/OrganizationConnections/UpdateOrganizationConnectionCommand.cs @@ -1,6 +1,7 @@ using Bit.Core.Entities; using Bit.Core.Exceptions; using Bit.Core.Models.Data.Organizations.OrganizationConnections; +using Bit.Core.Models.OrganizationConnectionConfigs; using Bit.Core.OrganizationFeatures.OrganizationConnections.Interfaces; using Bit.Core.Repositories; @@ -15,7 +16,7 @@ public class UpdateOrganizationConnectionCommand : IUpdateOrganizationConnection _organizationConnectionRepository = organizationConnectionRepository; } - public async Task UpdateAsync(OrganizationConnectionData connectionData) where T : new() + public async Task UpdateAsync(OrganizationConnectionData connectionData) where T : IConnectionConfig { if (!connectionData.Id.HasValue) { diff --git a/src/Core/OrganizationFeatures/OrganizationSponsorships/FamiliesForEnterprise/Cloud/ValidateBillingSyncKeyCommand.cs b/src/Core/OrganizationFeatures/OrganizationConnections/ValidateBillingSyncKeyCommand.cs similarity index 70% rename from src/Core/OrganizationFeatures/OrganizationSponsorships/FamiliesForEnterprise/Cloud/ValidateBillingSyncKeyCommand.cs rename to src/Core/OrganizationFeatures/OrganizationConnections/ValidateBillingSyncKeyCommand.cs index 19c4398a70..a764bbcf23 100644 --- a/src/Core/OrganizationFeatures/OrganizationSponsorships/FamiliesForEnterprise/Cloud/ValidateBillingSyncKeyCommand.cs +++ b/src/Core/OrganizationFeatures/OrganizationConnections/ValidateBillingSyncKeyCommand.cs @@ -1,20 +1,17 @@ using Bit.Core.Entities; using Bit.Core.Exceptions; -using Bit.Core.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterprise.Interfaces; +using Bit.Core.OrganizationFeatures.OrganizationConnections.Interfaces; using Bit.Core.Repositories; -namespace Bit.Core.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterprise.Cloud; +namespace Bit.Core.OrganizationFeatures.OrganizationConnections; public class ValidateBillingSyncKeyCommand : IValidateBillingSyncKeyCommand { - private readonly IOrganizationSponsorshipRepository _organizationSponsorshipRepository; private readonly IOrganizationApiKeyRepository _apiKeyRepository; public ValidateBillingSyncKeyCommand( - IOrganizationSponsorshipRepository organizationSponsorshipRepository, IOrganizationApiKeyRepository organizationApiKeyRepository) { - _organizationSponsorshipRepository = organizationSponsorshipRepository; _apiKeyRepository = organizationApiKeyRepository; } diff --git a/src/Core/OrganizationFeatures/OrganizationLicenses/Cloud/CloudGetOrganizationLicenseQuery.cs b/src/Core/OrganizationFeatures/OrganizationLicenses/Cloud/CloudGetOrganizationLicenseQuery.cs new file mode 100644 index 0000000000..ff8a6d34fb --- /dev/null +++ b/src/Core/OrganizationFeatures/OrganizationLicenses/Cloud/CloudGetOrganizationLicenseQuery.cs @@ -0,0 +1,38 @@ +using Bit.Core.Entities; +using Bit.Core.Exceptions; +using Bit.Core.Models.Business; +using Bit.Core.OrganizationFeatures.OrganizationLicenses.Interfaces; +using Bit.Core.Repositories; +using Bit.Core.Services; + +namespace Bit.Core.OrganizationFeatures.OrganizationLicenses; + +public class CloudGetOrganizationLicenseQuery : ICloudGetOrganizationLicenseQuery +{ + private readonly IInstallationRepository _installationRepository; + private readonly IPaymentService _paymentService; + private readonly ILicensingService _licensingService; + + public CloudGetOrganizationLicenseQuery( + IInstallationRepository installationRepository, + IPaymentService paymentService, + ILicensingService licensingService) + { + _installationRepository = installationRepository; + _paymentService = paymentService; + _licensingService = licensingService; + } + + public async Task GetLicenseAsync(Organization organization, Guid installationId, + int? version = null) + { + var installation = await _installationRepository.GetByIdAsync(installationId); + if (installation is not { Enabled: true }) + { + throw new BadRequestException("Invalid installation id"); + } + + var subInfo = await _paymentService.GetSubscriptionAsync(organization); + return new OrganizationLicense(organization, subInfo, installationId, _licensingService, version); + } +} diff --git a/src/Core/OrganizationFeatures/OrganizationLicenses/Interfaces/IGetOrganizationLicenseQuery.cs b/src/Core/OrganizationFeatures/OrganizationLicenses/Interfaces/IGetOrganizationLicenseQuery.cs new file mode 100644 index 0000000000..2c66833e63 --- /dev/null +++ b/src/Core/OrganizationFeatures/OrganizationLicenses/Interfaces/IGetOrganizationLicenseQuery.cs @@ -0,0 +1,15 @@ +using Bit.Core.Entities; +using Bit.Core.Models.Business; + +namespace Bit.Core.OrganizationFeatures.OrganizationLicenses.Interfaces; + +public interface ICloudGetOrganizationLicenseQuery +{ + Task GetLicenseAsync(Organization organization, Guid installationId, + int? version = null); +} + +public interface ISelfHostedGetOrganizationLicenseQuery +{ + Task GetLicenseAsync(Organization organization, OrganizationConnection billingSyncConnection); +} diff --git a/src/Core/OrganizationFeatures/OrganizationLicenses/SelfHosted/SelfHostedGetOrganizationLicenseQuery.cs b/src/Core/OrganizationFeatures/OrganizationLicenses/SelfHosted/SelfHostedGetOrganizationLicenseQuery.cs new file mode 100644 index 0000000000..84ae0a27db --- /dev/null +++ b/src/Core/OrganizationFeatures/OrganizationLicenses/SelfHosted/SelfHostedGetOrganizationLicenseQuery.cs @@ -0,0 +1,66 @@ +using Bit.Core.Context; +using Bit.Core.Entities; +using Bit.Core.Exceptions; +using Bit.Core.Models.Api.OrganizationLicenses; +using Bit.Core.Models.Business; +using Bit.Core.Models.OrganizationConnectionConfigs; +using Bit.Core.OrganizationFeatures.OrganizationLicenses.Interfaces; +using Bit.Core.Services; +using Bit.Core.Settings; +using Microsoft.Extensions.Logging; + +namespace Bit.Core.OrganizationFeatures.OrganizationLicenses; + +public class SelfHostedGetOrganizationLicenseQuery : BaseIdentityClientService, ISelfHostedGetOrganizationLicenseQuery +{ + private readonly IGlobalSettings _globalSettings; + + public SelfHostedGetOrganizationLicenseQuery(IHttpClientFactory httpFactory, IGlobalSettings globalSettings, ILogger logger, ICurrentContext currentContext) + : base( + httpFactory, + globalSettings.Installation.ApiUri, + globalSettings.Installation.IdentityUri, + "api.licensing", + $"installation.{globalSettings.Installation.Id}", + globalSettings.Installation.Key, + logger) + { + _globalSettings = globalSettings; + } + + public async Task GetLicenseAsync(Organization organization, OrganizationConnection billingSyncConnection) + { + if (!_globalSettings.SelfHosted) + { + throw new BadRequestException("This action is only available for self-hosted."); + } + + if (!_globalSettings.EnableCloudCommunication) + { + throw new BadRequestException("Cloud communication is disabled in global settings"); + } + + if (!billingSyncConnection.Validate(out var exception)) + { + throw new BadRequestException(exception); + } + + var billingSyncConfig = billingSyncConnection.GetConfig(); + var cloudOrganizationId = billingSyncConfig.CloudOrganizationId; + + var response = await SendAsync( + HttpMethod.Get, $"licenses/organization/{cloudOrganizationId}", new SelfHostedOrganizationLicenseRequestModel() + { + BillingSyncKey = billingSyncConfig.BillingSyncKey, + LicenseKey = organization.LicenseKey, + }, true); + + if (response == null) + { + _logger.LogDebug("Organization License sync failed for '{OrgId}'", organization.Id); + throw new BadRequestException("An error has occurred. Check your internet connection and ensure the billing token is correct."); + } + + return response; + } +} diff --git a/src/Core/OrganizationFeatures/OrganizationServiceCollectionExtensions.cs b/src/Core/OrganizationFeatures/OrganizationServiceCollectionExtensions.cs index 18c2f44dc9..b8e2a775e2 100644 --- a/src/Core/OrganizationFeatures/OrganizationServiceCollectionExtensions.cs +++ b/src/Core/OrganizationFeatures/OrganizationServiceCollectionExtensions.cs @@ -7,6 +7,8 @@ using Bit.Core.OrganizationFeatures.OrganizationCollections; using Bit.Core.OrganizationFeatures.OrganizationCollections.Interfaces; using Bit.Core.OrganizationFeatures.OrganizationConnections; using Bit.Core.OrganizationFeatures.OrganizationConnections.Interfaces; +using Bit.Core.OrganizationFeatures.OrganizationLicenses; +using Bit.Core.OrganizationFeatures.OrganizationLicenses.Interfaces; using Bit.Core.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterprise; using Bit.Core.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterprise.Cloud; using Bit.Core.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterprise.Interfaces; @@ -32,6 +34,7 @@ public static class OrganizationServiceCollectionExtensions services.AddOrganizationApiKeyCommandsQueries(); services.AddOrganizationCollectionCommands(); services.AddOrganizationGroupCommands(); + services.AddOrganizationLicenseCommandQueries(); } private static void AddOrganizationConnectionCommands(this IServiceCollection services) @@ -85,6 +88,12 @@ public static class OrganizationServiceCollectionExtensions services.AddScoped(); } + private static void AddOrganizationLicenseCommandQueries(this IServiceCollection services) + { + services.AddScoped(); + services.AddScoped(); + } + private static void AddTokenizers(this IServiceCollection services) { services.AddSingleton>(serviceProvider => diff --git a/src/Core/OrganizationFeatures/OrganizationSponsorships/FamiliesForEnterprise/SelfHosted/SelfHostedSyncSponsorshipsCommand.cs b/src/Core/OrganizationFeatures/OrganizationSponsorships/FamiliesForEnterprise/SelfHosted/SelfHostedSyncSponsorshipsCommand.cs index eed143838e..0d22b53bad 100644 --- a/src/Core/OrganizationFeatures/OrganizationSponsorships/FamiliesForEnterprise/SelfHosted/SelfHostedSyncSponsorshipsCommand.cs +++ b/src/Core/OrganizationFeatures/OrganizationSponsorships/FamiliesForEnterprise/SelfHosted/SelfHostedSyncSponsorshipsCommand.cs @@ -48,20 +48,13 @@ public class SelfHostedSyncSponsorshipsCommand : BaseIdentityClientService, ISel { throw new BadRequestException("Failed to sync instance with cloud - Cloud communication is disabled in global settings"); } - if (!billingSyncConnection.Enabled) + + if (!billingSyncConnection.Validate(out var exception)) { - throw new BadRequestException($"Billing Sync Key disabled for organization {organizationId}"); - } - if (string.IsNullOrWhiteSpace(billingSyncConnection.Config)) - { - throw new BadRequestException($"No Billing Sync Key known for organization {organizationId}"); - } - var billingSyncConfig = billingSyncConnection.GetConfig(); - if (billingSyncConfig == null || string.IsNullOrWhiteSpace(billingSyncConfig.BillingSyncKey)) - { - throw new BadRequestException($"Failed to get Billing Sync Key for organization {organizationId}"); + throw new BadRequestException(exception); } + var billingSyncConfig = billingSyncConnection.GetConfig(); var organizationSponsorshipsDict = (await _organizationSponsorshipRepository.GetManyBySponsoringOrganizationAsync(organizationId)) .ToDictionary(i => i.SponsoringOrganizationUserId); if (!organizationSponsorshipsDict.Any()) diff --git a/src/Core/Repositories/IProviderUserRepository.cs b/src/Core/Repositories/IProviderUserRepository.cs index 4a5db368ee..ba920a575d 100644 --- a/src/Core/Repositories/IProviderUserRepository.cs +++ b/src/Core/Repositories/IProviderUserRepository.cs @@ -11,7 +11,7 @@ public interface IProviderUserRepository : IRepository Task> GetManyByUserAsync(Guid userId); Task GetByProviderUserAsync(Guid providerId, Guid userId); Task> GetManyByProviderAsync(Guid providerId, ProviderUserType? type = null); - Task> GetManyDetailsByProviderAsync(Guid providerId); + Task> GetManyDetailsByProviderAsync(Guid providerId, ProviderUserStatusType? status = null); Task> GetManyDetailsByUserAsync(Guid userId, ProviderUserStatusType? status = null); Task> GetManyOrganizationDetailsByUserAsync(Guid userId, ProviderUserStatusType? status = null); diff --git a/src/Core/SecretsManager/Commands/ServiceAccounts/Interfaces/ICreateServiceAccountCommand.cs b/src/Core/SecretsManager/Commands/ServiceAccounts/Interfaces/ICreateServiceAccountCommand.cs index 42eaf6824f..48e368b842 100644 --- a/src/Core/SecretsManager/Commands/ServiceAccounts/Interfaces/ICreateServiceAccountCommand.cs +++ b/src/Core/SecretsManager/Commands/ServiceAccounts/Interfaces/ICreateServiceAccountCommand.cs @@ -4,5 +4,5 @@ namespace Bit.Core.SecretsManager.Commands.ServiceAccounts.Interfaces; public interface ICreateServiceAccountCommand { - Task CreateAsync(ServiceAccount serviceAccount); + Task CreateAsync(ServiceAccount serviceAccount, Guid userId); } diff --git a/src/Core/SecretsManager/Repositories/IAccessPolicyRepository.cs b/src/Core/SecretsManager/Repositories/IAccessPolicyRepository.cs index 3450fdc800..dbe05074fa 100644 --- a/src/Core/SecretsManager/Repositories/IAccessPolicyRepository.cs +++ b/src/Core/SecretsManager/Repositories/IAccessPolicyRepository.cs @@ -8,7 +8,8 @@ public interface IAccessPolicyRepository Task> CreateManyAsync(List baseAccessPolicies); Task AccessPolicyExists(BaseAccessPolicy baseAccessPolicy); Task GetByIdAsync(Guid id); - Task?> GetManyByProjectId(Guid id); + Task> GetManyByGrantedProjectIdAsync(Guid id); + Task> GetManyByGrantedServiceAccountIdAsync(Guid id); Task ReplaceAsync(BaseAccessPolicy baseAccessPolicy); Task DeleteAsync(Guid id); } diff --git a/src/Core/Services/IOrganizationService.cs b/src/Core/Services/IOrganizationService.cs index f3f3f16139..5383c1a3e3 100644 --- a/src/Core/Services/IOrganizationService.cs +++ b/src/Core/Services/IOrganizationService.cs @@ -56,9 +56,6 @@ public interface IOrganizationService IEnumerable organizationUserIds, Guid? deletingUserId); Task UpdateUserGroupsAsync(OrganizationUser organizationUser, IEnumerable groupIds, Guid? loggedInUserId); Task UpdateUserResetPasswordEnrollmentAsync(Guid organizationId, Guid userId, string resetPasswordKey, Guid? callingUserId); - Task GenerateLicenseAsync(Guid organizationId, Guid installationId); - Task GenerateLicenseAsync(Organization organization, Guid installationId, - int? version = null); Task ImportAsync(Guid organizationId, Guid? importingUserId, IEnumerable groups, IEnumerable newUsers, IEnumerable removeUserExternalIds, bool overwriteExisting); diff --git a/src/Core/Services/Implementations/OrganizationService.cs b/src/Core/Services/Implementations/OrganizationService.cs index f2b6f8b520..b2564a9432 100644 --- a/src/Core/Services/Implementations/OrganizationService.cs +++ b/src/Core/Services/Implementations/OrganizationService.cs @@ -2,6 +2,7 @@ using Bit.Core.Context; using Bit.Core.Entities; using Bit.Core.Enums; +using Bit.Core.Enums.Provider; using Bit.Core.Exceptions; using Bit.Core.Models.Business; using Bit.Core.Models.Data; @@ -43,6 +44,8 @@ public class OrganizationService : IOrganizationService private readonly IOrganizationConnectionRepository _organizationConnectionRepository; private readonly ICurrentContext _currentContext; private readonly ILogger _logger; + private readonly IProviderOrganizationRepository _providerOrganizationRepository; + private readonly IProviderUserRepository _providerUserRepository; public OrganizationService( IOrganizationRepository organizationRepository, @@ -69,7 +72,9 @@ public class OrganizationService : IOrganizationService IOrganizationApiKeyRepository organizationApiKeyRepository, IOrganizationConnectionRepository organizationConnectionRepository, ICurrentContext currentContext, - ILogger logger) + ILogger logger, + IProviderOrganizationRepository providerOrganizationRepository, + IProviderUserRepository providerUserRepository) { _organizationRepository = organizationRepository; _organizationUserRepository = organizationUserRepository; @@ -96,6 +101,8 @@ public class OrganizationService : IOrganizationService _organizationConnectionRepository = organizationConnectionRepository; _currentContext = currentContext; _logger = logger; + _providerOrganizationRepository = providerOrganizationRepository; + _providerUserRepository = providerUserRepository; } public async Task ReplacePaymentMethodAsync(Guid organizationId, string paymentToken, @@ -1236,6 +1243,7 @@ public class OrganizationService : IOrganizationService Type = invite.Type.Value, Status = OrganizationUserStatusType.Invited, AccessAll = invite.AccessAll, + AccessSecretsManager = invite.AccessSecretsManager, ExternalId = externalId, CreationDate = DateTime.UtcNow, RevisionDate = DateTime.UtcNow, @@ -1637,8 +1645,19 @@ public class OrganizationService : IOrganizationService throw new BadRequestException(failureMessage); } - var ownerEmails = (await _organizationUserRepository.GetManyByMinimumRoleAsync(organization.Id, - OrganizationUserType.Owner)).Select(u => u.Email).Distinct(); + var providerOrg = await this._providerOrganizationRepository.GetByOrganizationId(organization.Id); + + IEnumerable ownerEmails; + if (providerOrg != null) + { + ownerEmails = (await _providerUserRepository.GetManyDetailsByProviderAsync(providerOrg.ProviderId, ProviderUserStatusType.Confirmed)) + .Select(u => u.Email).Distinct(); + } + else + { + ownerEmails = (await _organizationUserRepository.GetManyByMinimumRoleAsync(organization.Id, + OrganizationUserType.Owner)).Select(u => u.Email).Distinct(); + } var initialSeatCount = organization.Seats.Value; await AdjustSeatsAsync(organization, seatsToAdd, prorationDate, ownerEmails); @@ -1910,30 +1929,6 @@ public class OrganizationService : IOrganizationService EventType.OrganizationUser_ResetPassword_Enroll : EventType.OrganizationUser_ResetPassword_Withdraw); } - public async Task GenerateLicenseAsync(Guid organizationId, Guid installationId) - { - var organization = await GetOrgById(organizationId); - return await GenerateLicenseAsync(organization, installationId); - } - - public async Task GenerateLicenseAsync(Organization organization, Guid installationId, - int? version = null) - { - if (organization == null) - { - throw new NotFoundException(); - } - - var installation = await _installationRepository.GetByIdAsync(installationId); - if (installation == null || !installation.Enabled) - { - throw new BadRequestException("Invalid installation id"); - } - - var subInfo = await _paymentService.GetSubscriptionAsync(organization); - return new OrganizationLicense(organization, subInfo, installationId, _licensingService, version); - } - public async Task InviteUserAsync(Guid organizationId, Guid? invitingUserId, string email, OrganizationUserType type, bool accessAll, string externalId, IEnumerable collections, IEnumerable groups) diff --git a/src/Core/Services/Implementations/UserService.cs b/src/Core/Services/Implementations/UserService.cs index fed83f0a0c..3045797490 100644 --- a/src/Core/Services/Implementations/UserService.cs +++ b/src/Core/Services/Implementations/UserService.cs @@ -561,10 +561,13 @@ public class UserService : UserManager, IUserService, IDisposable return result; } + var now = DateTime.UtcNow; + user.Key = key; user.Email = newEmail; user.EmailVerified = true; - user.RevisionDate = user.AccountRevisionDate = DateTime.UtcNow; + user.RevisionDate = user.AccountRevisionDate = now; + user.LastEmailChangeDate = now; await _userRepository.ReplaceAsync(user); if (user.Gateway == GatewayType.Stripe) @@ -618,7 +621,9 @@ public class UserService : UserManager, IUserService, IDisposable return result; } - user.RevisionDate = user.AccountRevisionDate = DateTime.UtcNow; + var now = DateTime.UtcNow; + user.RevisionDate = user.AccountRevisionDate = now; + user.LastPasswordChangeDate = now; user.Key = key; user.MasterPasswordHint = passwordHint; @@ -845,7 +850,9 @@ public class UserService : UserManager, IUserService, IDisposable return result; } - user.RevisionDate = user.AccountRevisionDate = DateTime.UtcNow; + var now = DateTime.UtcNow; + user.RevisionDate = user.AccountRevisionDate = now; + user.LastKdfChangeDate = now; user.Key = key; user.Kdf = kdf; user.KdfIterations = kdfIterations; @@ -870,7 +877,9 @@ public class UserService : UserManager, IUserService, IDisposable if (await CheckPasswordAsync(user, masterPassword)) { - user.RevisionDate = user.AccountRevisionDate = DateTime.UtcNow; + var now = DateTime.UtcNow; + user.RevisionDate = user.AccountRevisionDate = now; + user.LastKeyRotationDate = now; user.SecurityStamp = Guid.NewGuid().ToString(); user.Key = key; user.PrivateKey = privateKey; diff --git a/src/Core/Utilities/CoreHelpers.cs b/src/Core/Utilities/CoreHelpers.cs index b925550d77..27e4551611 100644 --- a/src/Core/Utilities/CoreHelpers.cs +++ b/src/Core/Utilities/CoreHelpers.cs @@ -692,6 +692,15 @@ public static class CoreHelpers default: break; } + + // Secrets Manager + foreach (var org in group) + { + if (org.AccessSecretsManager) + { + claims.Add(new KeyValuePair(Claims.SecretsManagerAccess, org.Id.ToString())); + } + } } } diff --git a/src/Events/Startup.cs b/src/Events/Startup.cs index 9aee5425cd..50147fcda5 100644 --- a/src/Events/Startup.cs +++ b/src/Events/Startup.cs @@ -29,6 +29,9 @@ public class Startup // Settings var globalSettings = services.AddGlobalSettingsServices(Configuration, Environment); + // Data Protection + services.AddCustomDataProtectionServices(Environment, globalSettings); + // Repositories services.AddDatabaseRepositories(globalSettings); diff --git a/src/Identity/IdentityServer/ApiResources.cs b/src/Identity/IdentityServer/ApiResources.cs index 5d212f99bf..d23c06d7db 100644 --- a/src/Identity/IdentityServer/ApiResources.cs +++ b/src/Identity/IdentityServer/ApiResources.cs @@ -25,6 +25,7 @@ public class ApiResources Claims.OrganizationCustom, Claims.ProviderAdmin, Claims.ProviderServiceUser, + Claims.SecretsManagerAccess, }), new(ApiScopes.Internal, new[] { JwtClaimTypes.Subject }), new(ApiScopes.ApiPush, new[] { JwtClaimTypes.Subject }), diff --git a/src/Infrastructure.Dapper/DapperHelpers.cs b/src/Infrastructure.Dapper/DapperHelpers.cs index bef1f39741..9f40e56000 100644 --- a/src/Infrastructure.Dapper/DapperHelpers.cs +++ b/src/Infrastructure.Dapper/DapperHelpers.cs @@ -59,7 +59,7 @@ public static class DapperHelpers public static DataTable ToTvp(this IEnumerable orgUsers) { var table = new DataTable(); - table.SetTypeName("[dbo].[OrganizationUserType]"); + table.SetTypeName("[dbo].[OrganizationUserType2]"); var columnData = new List<(string name, Type type, Func getter)> { @@ -76,6 +76,7 @@ public static class DapperHelpers (nameof(OrganizationUser.RevisionDate), typeof(DateTime), ou => ou.RevisionDate), (nameof(OrganizationUser.Permissions), typeof(string), ou => ou.Permissions), (nameof(OrganizationUser.ResetPasswordKey), typeof(string), ou => ou.ResetPasswordKey), + (nameof(OrganizationUser.AccessSecretsManager), typeof(bool), ou => ou.AccessSecretsManager), }; return orgUsers.BuildTable(table, columnData); diff --git a/src/Infrastructure.Dapper/Repositories/CipherRepository.cs b/src/Infrastructure.Dapper/Repositories/CipherRepository.cs index 19c895d9fd..8045aaf660 100644 --- a/src/Infrastructure.Dapper/Repositories/CipherRepository.cs +++ b/src/Infrastructure.Dapper/Repositories/CipherRepository.cs @@ -321,6 +321,8 @@ public class CipherRepository : Repository, ICipherRepository } cmd.Parameters.Add("@RevisionDate", SqlDbType.DateTime2).Value = user.RevisionDate; + cmd.Parameters.Add("@AccountRevisionDate", SqlDbType.DateTime2).Value = user.AccountRevisionDate; + cmd.Parameters.Add("@LastKeyRotationDate", SqlDbType.DateTime2).Value = user.LastKeyRotationDate; cmd.ExecuteNonQuery(); } diff --git a/src/Infrastructure.Dapper/Repositories/OrganizationUserRepository.cs b/src/Infrastructure.Dapper/Repositories/OrganizationUserRepository.cs index 60c6c204c7..ef3d5bfbbd 100644 --- a/src/Infrastructure.Dapper/Repositories/OrganizationUserRepository.cs +++ b/src/Infrastructure.Dapper/Repositories/OrganizationUserRepository.cs @@ -405,7 +405,7 @@ public class OrganizationUserRepository : Repository, IO using (var connection = new SqlConnection(_marsConnectionString)) { var results = await connection.ExecuteAsync( - $"[{Schema}].[{Table}_CreateMany]", + $"[{Schema}].[{Table}_CreateMany2]", new { OrganizationUsersInput = orgUsersTVP }, commandType: CommandType.StoredProcedure); } @@ -424,7 +424,7 @@ public class OrganizationUserRepository : Repository, IO using (var connection = new SqlConnection(_marsConnectionString)) { var results = await connection.ExecuteAsync( - $"[{Schema}].[{Table}_UpdateMany]", + $"[{Schema}].[{Table}_UpdateMany2]", new { OrganizationUsersInput = orgUsersTVP }, commandType: CommandType.StoredProcedure); } diff --git a/src/Infrastructure.Dapper/Repositories/ProviderUserRepository.cs b/src/Infrastructure.Dapper/Repositories/ProviderUserRepository.cs index 0e1138e146..a0e2b69896 100644 --- a/src/Infrastructure.Dapper/Repositories/ProviderUserRepository.cs +++ b/src/Infrastructure.Dapper/Repositories/ProviderUserRepository.cs @@ -84,13 +84,13 @@ public class ProviderUserRepository : Repository, IProviderU } } - public async Task> GetManyDetailsByProviderAsync(Guid providerId) + public async Task> GetManyDetailsByProviderAsync(Guid providerId, ProviderUserStatusType? status) { using (var connection = new SqlConnection(ConnectionString)) { var results = await connection.QueryAsync( "[dbo].[ProviderUserUserDetails_ReadByProviderId]", - new { ProviderId = providerId }, + new { ProviderId = providerId, Status = status }, commandType: CommandType.StoredProcedure); return results.ToList(); diff --git a/src/Infrastructure.EntityFramework/Repositories/BaseEntityFrameworkRepository.cs b/src/Infrastructure.EntityFramework/Repositories/BaseEntityFrameworkRepository.cs index a27a38e2b7..ec3e1f27dc 100644 --- a/src/Infrastructure.EntityFramework/Repositories/BaseEntityFrameworkRepository.cs +++ b/src/Infrastructure.EntityFramework/Repositories/BaseEntityFrameworkRepository.cs @@ -128,7 +128,9 @@ public abstract class BaseEntityFrameworkRepository entity.SecurityStamp = user.SecurityStamp; entity.Key = user.Key; entity.PrivateKey = user.PrivateKey; - entity.RevisionDate = DateTime.UtcNow; + entity.LastKeyRotationDate = user.LastKeyRotationDate; + entity.AccountRevisionDate = user.AccountRevisionDate; + entity.RevisionDate = user.RevisionDate; await dbContext.SaveChangesAsync(); } } diff --git a/src/Infrastructure.EntityFramework/Repositories/CipherRepository.cs b/src/Infrastructure.EntityFramework/Repositories/CipherRepository.cs index 096c905184..49b407018c 100644 --- a/src/Infrastructure.EntityFramework/Repositories/CipherRepository.cs +++ b/src/Infrastructure.EntityFramework/Repositories/CipherRepository.cs @@ -29,7 +29,7 @@ public class CipherRepository : Repository, var dbContext = GetDatabaseContext(scope); if (cipher.OrganizationId.HasValue) { - await dbContext.UserBumpAccountRevisionDateByCipherIdAsync(cipher.Id, cipher.OrganizationId); + await dbContext.UserBumpAccountRevisionDateByCipherIdAsync(cipher.Id, cipher.OrganizationId.Value); } else if (cipher.UserId.HasValue) { @@ -59,7 +59,7 @@ public class CipherRepository : Repository, await OrganizationUpdateStorage(cipherInfo.OrganizationId.Value); } - await dbContext.UserBumpAccountRevisionDateByCipherIdAsync(cipher.Id, cipherInfo.OrganizationId); + await dbContext.UserBumpAccountRevisionDateByCipherIdAsync(cipher.Id, cipherInfo.OrganizationId.Value); } else if (cipherInfo?.UserId != null) { @@ -107,7 +107,16 @@ public class CipherRepository : Repository, null; var entity = Mapper.Map((Core.Entities.Cipher)cipher); await dbContext.AddAsync(entity); - await dbContext.UserBumpAccountRevisionDateByCipherIdAsync(cipher.Id, cipher.OrganizationId.GetValueOrDefault()); + + if (cipher.OrganizationId.HasValue) + { + await dbContext.UserBumpAccountRevisionDateByCipherIdAsync(cipher.Id, cipher.OrganizationId.Value); + } + else if (cipher.UserId.HasValue) + { + await dbContext.UserBumpAccountRevisionDateAsync(cipher.UserId.Value); + } + await dbContext.SaveChangesAsync(); } return cipher; @@ -458,7 +467,16 @@ public class CipherRepository : Repository, } var mappedEntity = Mapper.Map((Core.Entities.Cipher)cipher); dbContext.Entry(entity).CurrentValues.SetValues(mappedEntity); - await dbContext.UserBumpAccountRevisionDateByCipherIdAsync(cipher.Id, cipher.OrganizationId.GetValueOrDefault()); + + if (cipher.OrganizationId.HasValue) + { + await dbContext.UserBumpAccountRevisionDateByCipherIdAsync(cipher.Id, cipher.OrganizationId.Value); + } + else if (cipher.UserId.HasValue) + { + await dbContext.UserBumpAccountRevisionDateAsync(cipher.UserId.Value); + } + await dbContext.SaveChangesAsync(); } } @@ -566,7 +584,15 @@ public class CipherRepository : Repository, } } - await dbContext.UserBumpAccountRevisionDateByCipherIdAsync(cipher.Id, cipher.OrganizationId.GetValueOrDefault()); + if (cipher.OrganizationId.HasValue) + { + await dbContext.UserBumpAccountRevisionDateByCipherIdAsync(cipher.Id, cipher.OrganizationId.Value); + } + else if (cipher.UserId.HasValue) + { + await dbContext.UserBumpAccountRevisionDateAsync(cipher.UserId.Value); + } + await dbContext.SaveChangesAsync(); return true; } @@ -677,7 +703,7 @@ public class CipherRepository : Repository, if (attachment.OrganizationId.HasValue) { await OrganizationUpdateStorage(cipher.OrganizationId.Value); - await dbContext.UserBumpAccountRevisionDateByCipherIdAsync(cipher.Id, cipher.OrganizationId); + await dbContext.UserBumpAccountRevisionDateByCipherIdAsync(cipher.Id, cipher.OrganizationId.Value); } else if (attachment.UserId.HasValue) { diff --git a/src/Infrastructure.EntityFramework/Repositories/DatabaseContextExtensions.cs b/src/Infrastructure.EntityFramework/Repositories/DatabaseContextExtensions.cs index 8180ec15ec..0535c0265e 100644 --- a/src/Infrastructure.EntityFramework/Repositories/DatabaseContextExtensions.cs +++ b/src/Infrastructure.EntityFramework/Repositories/DatabaseContextExtensions.cs @@ -34,7 +34,7 @@ public static class DatabaseContextExtensions UpdateUserRevisionDate(users); } - public static async Task UserBumpAccountRevisionDateByCipherIdAsync(this DatabaseContext context, Guid cipherId, Guid? organizationId) + public static async Task UserBumpAccountRevisionDateByCipherIdAsync(this DatabaseContext context, Guid cipherId, Guid organizationId) { var query = new UserBumpAccountRevisionDateByCipherIdQuery(cipherId, organizationId); var users = await query.Run(context).ToListAsync(); diff --git a/src/Infrastructure.EntityFramework/Repositories/ProviderUserRepository.cs b/src/Infrastructure.EntityFramework/Repositories/ProviderUserRepository.cs index 76236a1c38..cad923c26c 100644 --- a/src/Infrastructure.EntityFramework/Repositories/ProviderUserRepository.cs +++ b/src/Infrastructure.EntityFramework/Repositories/ProviderUserRepository.cs @@ -103,7 +103,7 @@ public class ProviderUserRepository : return await query.FirstOrDefaultAsync(); } } - public async Task> GetManyDetailsByProviderAsync(Guid providerId) + public async Task> GetManyDetailsByProviderAsync(Guid providerId, ProviderUserStatusType? status) { using (var scope = ServiceScopeFactory.CreateScope()) { @@ -113,17 +113,19 @@ public class ProviderUserRepository : on pu.UserId equals u.Id into u_g from u in u_g.DefaultIfEmpty() select new { pu, u }; - var data = await view.Where(e => e.pu.ProviderId == providerId).Select(e => new ProviderUserUserDetails - { - Id = e.pu.Id, - UserId = e.pu.UserId, - ProviderId = e.pu.ProviderId, - Name = e.u.Name, - Email = e.u.Email ?? e.pu.Email, - Status = e.pu.Status, - Type = e.pu.Type, - Permissions = e.pu.Permissions, - }).ToArrayAsync(); + var data = await view + .Where(e => e.pu.ProviderId == providerId && (status == null || e.pu.Status == status)) + .Select(e => new ProviderUserUserDetails + { + Id = e.pu.Id, + UserId = e.pu.UserId, + ProviderId = e.pu.ProviderId, + Name = e.u.Name, + Email = e.u.Email ?? e.pu.Email, + Status = e.pu.Status, + Type = e.pu.Type, + Permissions = e.pu.Permissions, + }).ToArrayAsync(); return data; } } diff --git a/src/Infrastructure.EntityFramework/Repositories/Queries/OrganizationUserOrganizationDetailsViewQuery.cs b/src/Infrastructure.EntityFramework/Repositories/Queries/OrganizationUserOrganizationDetailsViewQuery.cs index 1e9968cffe..aecad397b5 100644 --- a/src/Infrastructure.EntityFramework/Repositories/Queries/OrganizationUserOrganizationDetailsViewQuery.cs +++ b/src/Infrastructure.EntityFramework/Repositories/Queries/OrganizationUserOrganizationDetailsViewQuery.cs @@ -37,6 +37,7 @@ public class OrganizationUserOrganizationDetailsViewQuery : IQuery { private readonly Guid _cipherId; - private readonly Guid? _organizationId; + private readonly Guid _organizationId; - public UserBumpAccountRevisionDateByCipherIdQuery(Cipher cipher) - { - _cipherId = cipher.Id; - _organizationId = cipher.OrganizationId; - } - - public UserBumpAccountRevisionDateByCipherIdQuery(Guid cipherId, Guid? organizationId) + public UserBumpAccountRevisionDateByCipherIdQuery(Guid cipherId, Guid organizationId) { _cipherId = cipherId; _organizationId = organizationId; diff --git a/src/Notifications/HeartbeatHostedService.cs b/src/Notifications/HeartbeatHostedService.cs index 717fdeb784..6dcfe7189f 100644 --- a/src/Notifications/HeartbeatHostedService.cs +++ b/src/Notifications/HeartbeatHostedService.cs @@ -13,7 +13,7 @@ public class HeartbeatHostedService : IHostedService, IDisposable private CancellationTokenSource _cts; public HeartbeatHostedService( - ILogger logger, + ILogger logger, IHubContext hubContext, GlobalSettings globalSettings) { @@ -49,7 +49,7 @@ public class HeartbeatHostedService : IHostedService, IDisposable while (!cancellationToken.IsCancellationRequested) { await _hubContext.Clients.All.SendAsync("Heartbeat"); - await Task.Delay(120000); + await Task.Delay(120000, cancellationToken); } _logger.LogWarning("Done with heartbeat."); } diff --git a/src/Sql/Sql.sqlproj b/src/Sql/Sql.sqlproj index 8995419d60..1ffe20cc11 100644 --- a/src/Sql/Sql.sqlproj +++ b/src/Sql/Sql.sqlproj @@ -238,6 +238,7 @@ + @@ -258,6 +259,7 @@ + @@ -400,6 +402,7 @@ + diff --git a/src/Sql/dbo/Stored Procedures/OrganizationUser_Create.sql b/src/Sql/dbo/Stored Procedures/OrganizationUser_Create.sql index 95795067d4..887f874b00 100644 --- a/src/Sql/dbo/Stored Procedures/OrganizationUser_Create.sql +++ b/src/Sql/dbo/Stored Procedures/OrganizationUser_Create.sql @@ -11,7 +11,8 @@ @CreationDate DATETIME2(7), @RevisionDate DATETIME2(7), @Permissions NVARCHAR(MAX), - @ResetPasswordKey VARCHAR(MAX) + @ResetPasswordKey VARCHAR(MAX), + @AccessSecretsManager BIT = 0 AS BEGIN SET NOCOUNT ON @@ -30,7 +31,8 @@ BEGIN [CreationDate], [RevisionDate], [Permissions], - [ResetPasswordKey] + [ResetPasswordKey], + [AccessSecretsManager] ) VALUES ( @@ -46,6 +48,7 @@ BEGIN @CreationDate, @RevisionDate, @Permissions, - @ResetPasswordKey + @ResetPasswordKey, + @AccessSecretsManager ) END diff --git a/src/Sql/dbo/Stored Procedures/OrganizationUser_CreateMany2.sql b/src/Sql/dbo/Stored Procedures/OrganizationUser_CreateMany2.sql new file mode 100644 index 0000000000..0a07daeb3a --- /dev/null +++ b/src/Sql/dbo/Stored Procedures/OrganizationUser_CreateMany2.sql @@ -0,0 +1,42 @@ +CREATE PROCEDURE [dbo].[OrganizationUser_CreateMany2] + @OrganizationUsersInput [dbo].[OrganizationUserType2] READONLY +AS +BEGIN + SET NOCOUNT ON + + INSERT INTO [dbo].[OrganizationUser] + ( + [Id], + [OrganizationId], + [UserId], + [Email], + [Key], + [Status], + [Type], + [AccessAll], + [ExternalId], + [CreationDate], + [RevisionDate], + [Permissions], + [ResetPasswordKey], + [AccessSecretsManager] + ) + SELECT + OU.[Id], + OU.[OrganizationId], + OU.[UserId], + OU.[Email], + OU.[Key], + OU.[Status], + OU.[Type], + OU.[AccessAll], + OU.[ExternalId], + OU.[CreationDate], + OU.[RevisionDate], + OU.[Permissions], + OU.[ResetPasswordKey], + OU.[AccessSecretsManager] + FROM + @OrganizationUsersInput OU +END +GO diff --git a/src/Sql/dbo/Stored Procedures/OrganizationUser_CreateWithCollections.sql b/src/Sql/dbo/Stored Procedures/OrganizationUser_CreateWithCollections.sql index 55d5f9c084..98809a0ec2 100644 --- a/src/Sql/dbo/Stored Procedures/OrganizationUser_CreateWithCollections.sql +++ b/src/Sql/dbo/Stored Procedures/OrganizationUser_CreateWithCollections.sql @@ -12,12 +12,13 @@ @RevisionDate DATETIME2(7), @Permissions NVARCHAR(MAX), @ResetPasswordKey VARCHAR(MAX), - @Collections AS [dbo].[SelectionReadOnlyArray] READONLY + @Collections AS [dbo].[SelectionReadOnlyArray] READONLY, + @AccessSecretsManager BIT = 0 AS BEGIN SET NOCOUNT ON - EXEC [dbo].[OrganizationUser_Create] @Id, @OrganizationId, @UserId, @Email, @Key, @Status, @Type, @AccessAll, @ExternalId, @CreationDate, @RevisionDate, @Permissions, @ResetPasswordKey + EXEC [dbo].[OrganizationUser_Create] @Id, @OrganizationId, @UserId, @Email, @Key, @Status, @Type, @AccessAll, @ExternalId, @CreationDate, @RevisionDate, @Permissions, @ResetPasswordKey, @AccessSecretsManager ;WITH [AvailableCollectionsCTE] AS( SELECT diff --git a/src/Sql/dbo/Stored Procedures/OrganizationUser_Update.sql b/src/Sql/dbo/Stored Procedures/OrganizationUser_Update.sql index c8cfa08a46..a4565d7894 100644 --- a/src/Sql/dbo/Stored Procedures/OrganizationUser_Update.sql +++ b/src/Sql/dbo/Stored Procedures/OrganizationUser_Update.sql @@ -11,7 +11,8 @@ @CreationDate DATETIME2(7), @RevisionDate DATETIME2(7), @Permissions NVARCHAR(MAX), - @ResetPasswordKey VARCHAR(MAX) + @ResetPasswordKey VARCHAR(MAX), + @AccessSecretsManager BIT = 0 AS BEGIN SET NOCOUNT ON @@ -30,7 +31,8 @@ BEGIN [CreationDate] = @CreationDate, [RevisionDate] = @RevisionDate, [Permissions] = @Permissions, - [ResetPasswordKey] = @ResetPasswordKey + [ResetPasswordKey] = @ResetPasswordKey, + [AccessSecretsManager] = @AccessSecretsManager WHERE [Id] = @Id diff --git a/src/Sql/dbo/Stored Procedures/OrganizationUser_UpdateMany2.sql b/src/Sql/dbo/Stored Procedures/OrganizationUser_UpdateMany2.sql new file mode 100644 index 0000000000..13427e8dc4 --- /dev/null +++ b/src/Sql/dbo/Stored Procedures/OrganizationUser_UpdateMany2.sql @@ -0,0 +1,34 @@ +CREATE PROCEDURE [dbo].[OrganizationUser_UpdateMany2] + @OrganizationUsersInput [dbo].[OrganizationUserType2] READONLY +AS +BEGIN + SET NOCOUNT ON + + UPDATE + OU + SET + [OrganizationId] = OUI.[OrganizationId], + [UserId] = OUI.[UserId], + [Email] = OUI.[Email], + [Key] = OUI.[Key], + [Status] = OUI.[Status], + [Type] = OUI.[Type], + [AccessAll] = OUI.[AccessAll], + [ExternalId] = OUI.[ExternalId], + [CreationDate] = OUI.[CreationDate], + [RevisionDate] = OUI.[RevisionDate], + [Permissions] = OUI.[Permissions], + [ResetPasswordKey] = OUI.[ResetPasswordKey], + [AccessSecretsManager] = OUI.[AccessSecretsManager] + FROM + [dbo].[OrganizationUser] OU + INNER JOIN + @OrganizationUsersInput OUI ON OU.Id = OUI.Id + + EXEC [dbo].[User_BumpManyAccountRevisionDates] + ( + SELECT UserId + FROM @OrganizationUsersInput + ) +END +GO diff --git a/src/Sql/dbo/Stored Procedures/OrganizationUser_UpdateWithCollections.sql b/src/Sql/dbo/Stored Procedures/OrganizationUser_UpdateWithCollections.sql index 20390a02cd..a4eabdaae5 100644 --- a/src/Sql/dbo/Stored Procedures/OrganizationUser_UpdateWithCollections.sql +++ b/src/Sql/dbo/Stored Procedures/OrganizationUser_UpdateWithCollections.sql @@ -12,12 +12,13 @@ @RevisionDate DATETIME2(7), @Permissions NVARCHAR(MAX), @ResetPasswordKey VARCHAR(MAX), - @Collections AS [dbo].[SelectionReadOnlyArray] READONLY + @Collections AS [dbo].[SelectionReadOnlyArray] READONLY, + @AccessSecretsManager BIT = 0 AS BEGIN SET NOCOUNT ON - EXEC [dbo].[OrganizationUser_Update] @Id, @OrganizationId, @UserId, @Email, @Key, @Status, @Type, @AccessAll, @ExternalId, @CreationDate, @RevisionDate, @Permissions, @ResetPasswordKey + EXEC [dbo].[OrganizationUser_Update] @Id, @OrganizationId, @UserId, @Email, @Key, @Status, @Type, @AccessAll, @ExternalId, @CreationDate, @RevisionDate, @Permissions, @ResetPasswordKey, @AccessSecretsManager -- Update UPDATE [Target] diff --git a/src/Sql/dbo/Stored Procedures/ProviderUserUserDetails_ReadByProviderId.sql b/src/Sql/dbo/Stored Procedures/ProviderUserUserDetails_ReadByProviderId.sql index cb9ce1da6e..a67d5cebaf 100644 --- a/src/Sql/dbo/Stored Procedures/ProviderUserUserDetails_ReadByProviderId.sql +++ b/src/Sql/dbo/Stored Procedures/ProviderUserUserDetails_ReadByProviderId.sql @@ -1,5 +1,6 @@ CREATE PROCEDURE [dbo].[ProviderUserUserDetails_ReadByProviderId] - @ProviderId UNIQUEIDENTIFIER + @ProviderId UNIQUEIDENTIFIER, + @Status TINYINT = NULL AS BEGIN SET NOCOUNT ON @@ -10,4 +11,5 @@ BEGIN [dbo].[ProviderUserUserDetailsView] WHERE [ProviderId] = @ProviderId + AND [Status] = COALESCE(@Status, [Status]) END diff --git a/src/Sql/dbo/Stored Procedures/User_Create.sql b/src/Sql/dbo/Stored Procedures/User_Create.sql index 96ef6cd5ca..65c5d21908 100644 --- a/src/Sql/dbo/Stored Procedures/User_Create.sql +++ b/src/Sql/dbo/Stored Procedures/User_Create.sql @@ -37,7 +37,11 @@ @FailedLoginCount INT = 0, @LastFailedLoginDate DATETIME2(7), @UnknownDeviceVerificationEnabled BIT = 1, - @AvatarColor VARCHAR(7) = NULL + @AvatarColor VARCHAR(7) = NULL, + @LastPasswordChangeDate DATETIME2(7) = NULL, + @LastKdfChangeDate DATETIME2(7) = NULL, + @LastKeyRotationDate DATETIME2(7) = NULL, + @LastEmailChangeDate DATETIME2(7) = NULL AS BEGIN SET NOCOUNT ON @@ -82,7 +86,11 @@ BEGIN [UnknownDeviceVerificationEnabled], [AvatarColor], [KdfMemory], - [KdfParallelism] + [KdfParallelism], + [LastPasswordChangeDate], + [LastKdfChangeDate], + [LastKeyRotationDate], + [LastEmailChangeDate] ) VALUES ( @@ -124,6 +132,10 @@ BEGIN @UnknownDeviceVerificationEnabled, @AvatarColor, @KdfMemory, - @KdfParallelism + @KdfParallelism, + @LastPasswordChangeDate, + @LastKdfChangeDate, + @LastKeyRotationDate, + @LastEmailChangeDate ) END diff --git a/src/Sql/dbo/Stored Procedures/User_Update.sql b/src/Sql/dbo/Stored Procedures/User_Update.sql index 0214a2a7cb..60a5119366 100644 --- a/src/Sql/dbo/Stored Procedures/User_Update.sql +++ b/src/Sql/dbo/Stored Procedures/User_Update.sql @@ -37,7 +37,11 @@ @FailedLoginCount INT, @LastFailedLoginDate DATETIME2(7), @UnknownDeviceVerificationEnabled BIT = 1, - @AvatarColor VARCHAR(7) + @AvatarColor VARCHAR(7), + @LastPasswordChangeDate DATETIME2(7) = NULL, + @LastKdfChangeDate DATETIME2(7) = NULL, + @LastKeyRotationDate DATETIME2(7) = NULL, + @LastEmailChangeDate DATETIME2(7) = NULL AS BEGIN SET NOCOUNT ON @@ -82,7 +86,11 @@ BEGIN [FailedLoginCount] = @FailedLoginCount, [LastFailedLoginDate] = @LastFailedLoginDate, [UnknownDeviceVerificationEnabled] = @UnknownDeviceVerificationEnabled, - [AvatarColor] = @AvatarColor + [AvatarColor] = @AvatarColor, + [LastPasswordChangeDate] = @LastPasswordChangeDate, + [LastKdfChangeDate] = @LastKdfChangeDate, + [LastKeyRotationDate] = @LastKeyRotationDate, + [LastEmailChangeDate] = @LastEmailChangeDate WHERE [Id] = @Id END diff --git a/src/Sql/dbo/Stored Procedures/User_UpdateKeys.sql b/src/Sql/dbo/Stored Procedures/User_UpdateKeys.sql index 8df14d0ab2..94bba39601 100644 --- a/src/Sql/dbo/Stored Procedures/User_UpdateKeys.sql +++ b/src/Sql/dbo/Stored Procedures/User_UpdateKeys.sql @@ -3,7 +3,9 @@ @SecurityStamp NVARCHAR(50), @Key NVARCHAR(MAX), @PrivateKey VARCHAR(MAX), - @RevisionDate DATETIME2(7) + @RevisionDate DATETIME2(7), + @AccountRevisionDate DATETIME2(7) = NULL, + @LastKeyRotationDate DATETIME2(7) = NULL AS BEGIN SET NOCOUNT ON @@ -15,7 +17,8 @@ BEGIN [Key] = @Key, [PrivateKey] = @PrivateKey, [RevisionDate] = @RevisionDate, - [AccountRevisionDate] = @RevisionDate + [AccountRevisionDate] = ISNULL(@AccountRevisionDate, @RevisionDate), + [LastKeyRotationDate] = @LastKeyRotationDate WHERE [Id] = @Id END \ No newline at end of file diff --git a/src/Sql/dbo/Tables/OrganizationUser.sql b/src/Sql/dbo/Tables/OrganizationUser.sql index fc1fa99505..37218532ce 100644 --- a/src/Sql/dbo/Tables/OrganizationUser.sql +++ b/src/Sql/dbo/Tables/OrganizationUser.sql @@ -12,6 +12,7 @@ [CreationDate] DATETIME2 (7) NOT NULL, [RevisionDate] DATETIME2 (7) NOT NULL, [Permissions] NVARCHAR (MAX) NULL, + [AccessSecretsManager] BIT NOT NULL CONSTRAINT [DF_OrganizationUser_SecretsManager] DEFAULT (0), CONSTRAINT [PK_OrganizationUser] PRIMARY KEY CLUSTERED ([Id] ASC), CONSTRAINT [FK_OrganizationUser_Organization] FOREIGN KEY ([OrganizationId]) REFERENCES [dbo].[Organization] ([Id]) ON DELETE CASCADE, CONSTRAINT [FK_OrganizationUser_User] FOREIGN KEY ([UserId]) REFERENCES [dbo].[User] ([Id]) diff --git a/src/Sql/dbo/Tables/User.sql b/src/Sql/dbo/Tables/User.sql index bfe236a8be..62ff0edf2b 100644 --- a/src/Sql/dbo/Tables/User.sql +++ b/src/Sql/dbo/Tables/User.sql @@ -37,7 +37,11 @@ [FailedLoginCount] INT CONSTRAINT [D_User_FailedLoginCount] DEFAULT ((0)) NOT NULL, [LastFailedLoginDate] DATETIME2 (7) NULL, [UnknownDeviceVerificationEnabled] BIT CONSTRAINT [D_User_UnknownDeviceVerificationEnabled] DEFAULT ((1)) NOT NULL, - [AvatarColor] VARCHAR(7) NULL, + [AvatarColor] VARCHAR (7) NULL, + [LastPasswordChangeDate] DATETIME2 (7) NULL, + [LastKdfChangeDate] DATETIME2 (7) NULL, + [LastKeyRotationDate] DATETIME2 (7) NULL, + [LastEmailChangeDate] DATETIME2 (7) NULL, CONSTRAINT [PK_User] PRIMARY KEY CLUSTERED ([Id] ASC) ); diff --git a/src/Sql/dbo/User Defined Types/OrganizationUserType2.sql b/src/Sql/dbo/User Defined Types/OrganizationUserType2.sql new file mode 100644 index 0000000000..eb06eff980 --- /dev/null +++ b/src/Sql/dbo/User Defined Types/OrganizationUserType2.sql @@ -0,0 +1,16 @@ +CREATE TYPE [dbo].[OrganizationUserType2] AS TABLE( + [Id] UNIQUEIDENTIFIER, + [OrganizationId] UNIQUEIDENTIFIER, + [UserId] UNIQUEIDENTIFIER, + [Email] NVARCHAR(256), + [Key] VARCHAR(MAX), + [Status] SMALLINT, + [Type] TINYINT, + [AccessAll] BIT, + [ExternalId] NVARCHAR(300), + [CreationDate] DATETIME2(7), + [RevisionDate] DATETIME2(7), + [Permissions] NVARCHAR(MAX), + [ResetPasswordKey] VARCHAR(MAX), + [AccessSecretsManager] BIT +) diff --git a/src/Sql/dbo/Views/OrganizationUserOrganizationDetailsView.sql b/src/Sql/dbo/Views/OrganizationUserOrganizationDetailsView.sql index 5c93a181b5..d475ca216e 100644 --- a/src/Sql/dbo/Views/OrganizationUserOrganizationDetailsView.sql +++ b/src/Sql/dbo/Views/OrganizationUserOrganizationDetailsView.sql @@ -39,7 +39,8 @@ SELECT OS.[FriendlyName] FamilySponsorshipFriendlyName, OS.[LastSyncDate] FamilySponsorshipLastSyncDate, OS.[ToDelete] FamilySponsorshipToDelete, - OS.[ValidUntil] FamilySponsorshipValidUntil + OS.[ValidUntil] FamilySponsorshipValidUntil, + OU.[AccessSecretsManager] FROM [dbo].[OrganizationUser] OU LEFT JOIN diff --git a/src/Sql/dbo/Views/OrganizationUserUserDetailsView.sql b/src/Sql/dbo/Views/OrganizationUserUserDetailsView.sql index e13097884a..4bc43f79ae 100644 --- a/src/Sql/dbo/Views/OrganizationUserUserDetailsView.sql +++ b/src/Sql/dbo/Views/OrganizationUserUserDetailsView.sql @@ -11,6 +11,7 @@ SELECT OU.[Status], OU.[Type], OU.[AccessAll], + OU.[AccessSecretsManager], OU.[ExternalId], SU.[ExternalId] SsoExternalId, OU.[Permissions], diff --git a/src/Sql/dbo/Views/ProviderUserProviderOrganizationDetailsView.sql b/src/Sql/dbo/Views/ProviderUserProviderOrganizationDetailsView.sql index 8e49f61359..199099deb3 100644 --- a/src/Sql/dbo/Views/ProviderUserProviderOrganizationDetailsView.sql +++ b/src/Sql/dbo/Views/ProviderUserProviderOrganizationDetailsView.sql @@ -30,7 +30,8 @@ SELECT PU.[Type], PO.[ProviderId], PU.[Id] ProviderUserId, - P.[Name] ProviderName + P.[Name] ProviderName, + O.[PlanType] FROM [dbo].[ProviderUser] PU INNER JOIN diff --git a/src/Sql/dbo_future/Stored Procedures/OrganizationUser_CreateMany.sql b/src/Sql/dbo_future/Stored Procedures/OrganizationUser_CreateMany.sql new file mode 100644 index 0000000000..371848cf9d --- /dev/null +++ b/src/Sql/dbo_future/Stored Procedures/OrganizationUser_CreateMany.sql @@ -0,0 +1,2 @@ +-- Created 2023-01 +-- DELETE FILE diff --git a/src/Sql/dbo_future/Stored Procedures/OrganizationUser_UpdateMany.sql b/src/Sql/dbo_future/Stored Procedures/OrganizationUser_UpdateMany.sql new file mode 100644 index 0000000000..371848cf9d --- /dev/null +++ b/src/Sql/dbo_future/Stored Procedures/OrganizationUser_UpdateMany.sql @@ -0,0 +1,2 @@ +-- Created 2023-01 +-- DELETE FILE diff --git a/src/Sql/dbo_future/User Defined Types/OrganizationUserType.sql b/src/Sql/dbo_future/User Defined Types/OrganizationUserType.sql new file mode 100644 index 0000000000..371848cf9d --- /dev/null +++ b/src/Sql/dbo_future/User Defined Types/OrganizationUserType.sql @@ -0,0 +1,2 @@ +-- Created 2023-01 +-- DELETE FILE diff --git a/test/Api.IntegrationTest/Helpers/OrganizationTestHelpers.cs b/test/Api.IntegrationTest/Helpers/OrganizationTestHelpers.cs index 7163d3e93b..e84d89713e 100644 --- a/test/Api.IntegrationTest/Helpers/OrganizationTestHelpers.cs +++ b/test/Api.IntegrationTest/Helpers/OrganizationTestHelpers.cs @@ -9,8 +9,7 @@ namespace Bit.Api.IntegrationTest.Helpers; public static class OrganizationTestHelpers { - public static async Task> SignUpAsync( - WebApplicationFactoryBase factory, + public static async Task> SignUpAsync(WebApplicationFactoryBase factory, PlanType plan = PlanType.Free, string ownerEmail = "integration-test@bitwarden.com", string name = "Integration Test Org", @@ -36,7 +35,8 @@ public static class OrganizationTestHelpers WebApplicationFactoryBase factory, Guid organizationId, string userEmail, - OrganizationUserType type + OrganizationUserType type, + bool accessSecretsManager = false ) where T : class { var userRepository = factory.GetService(); @@ -50,9 +50,10 @@ public static class OrganizationTestHelpers UserId = user.Id, Key = null, Type = type, - Status = OrganizationUserStatusType.Invited, + Status = OrganizationUserStatusType.Confirmed, AccessAll = false, ExternalId = null, + AccessSecretsManager = accessSecretsManager, }; await organizationUserRepository.CreateAsync(orgUser); diff --git a/test/Api.IntegrationTest/SecretsManager/Controllers/AccessPoliciesControllerTest.cs b/test/Api.IntegrationTest/SecretsManager/Controllers/AccessPoliciesControllerTest.cs index 74b0e062b9..9d42b67e8b 100644 --- a/test/Api.IntegrationTest/SecretsManager/Controllers/AccessPoliciesControllerTest.cs +++ b/test/Api.IntegrationTest/SecretsManager/Controllers/AccessPoliciesControllerTest.cs @@ -129,6 +129,26 @@ public class AccessPoliciesControllerTest : IClassFixture Assert.Null(test); } + [Fact] + public async Task GetProjectAccessPolicies_ReturnsEmpty() + { + var initialProject = await _projectRepository.CreateAsync(new Project + { + OrganizationId = _organization.Id, + Name = _mockEncryptedString, + }); + + var response = await _client.GetAsync($"/projects/{initialProject.Id}/access-policies"); + response.EnsureSuccessStatusCode(); + + var result = await response.Content.ReadFromJsonAsync(); + + Assert.NotNull(result); + Assert.Empty(result!.UserAccessPolicies); + Assert.Empty(result!.GroupAccessPolicies); + Assert.Empty(result!.ServiceAccountAccessPolicies); + } + [Fact] public async Task GetProjectAccessPolicies() { diff --git a/test/Api.IntegrationTest/SecretsManager/Controllers/ProjectsControllerTest.cs b/test/Api.IntegrationTest/SecretsManager/Controllers/ProjectsControllerTest.cs index 02dce96294..1b6db5c9c9 100644 --- a/test/Api.IntegrationTest/SecretsManager/Controllers/ProjectsControllerTest.cs +++ b/test/Api.IntegrationTest/SecretsManager/Controllers/ProjectsControllerTest.cs @@ -1,11 +1,9 @@ using System.Net; using System.Net.Http.Headers; using Bit.Api.IntegrationTest.Factories; -using Bit.Api.IntegrationTest.Helpers; using Bit.Api.Models.Response; using Bit.Api.SecretsManager.Models.Request; using Bit.Api.SecretsManager.Models.Response; -using Bit.Core.Entities; using Bit.Core.Enums; using Bit.Core.SecretsManager.Entities; using Bit.Core.SecretsManager.Repositories; @@ -22,7 +20,9 @@ public class ProjectsControllerTest : IClassFixture, IAsy private readonly HttpClient _client; private readonly ApiApplicationFactory _factory; private readonly IProjectRepository _projectRepository; - private Organization _organization = null!; + + private string _email = null!; + private SecretsManagerOrganizationHelper _organizationHelper = null!; public ProjectsControllerTest(ApiApplicationFactory factory) { @@ -33,20 +33,9 @@ public class ProjectsControllerTest : IClassFixture, IAsy public async Task InitializeAsync() { - var ownerEmail = $"integration-test{Guid.NewGuid()}@bitwarden.com"; - await _factory.LoginWithNewAccount(ownerEmail); - (_organization, _) = await OrganizationTestHelpers.SignUpAsync(_factory, ownerEmail: ownerEmail, billingEmail: ownerEmail); - var tokens = await _factory.LoginAsync(ownerEmail); - _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", tokens.Token); - } - - public async Task LoginAsNewOrgUser(OrganizationUserType type = OrganizationUserType.User) - { - var email = $"integration-test{Guid.NewGuid()}@bitwarden.com"; - await _factory.LoginWithNewAccount(email); - await OrganizationTestHelpers.CreateUserAsync(_factory, _organization.Id, email, type); - var tokens = await _factory.LoginAsync(email); - _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", tokens.Token); + _email = $"integration-test{Guid.NewGuid()}@bitwarden.com"; + await _factory.LoginWithNewAccount(_email); + _organizationHelper = new SecretsManagerOrganizationHelper(_factory, _email); } public Task DisposeAsync() @@ -55,12 +44,74 @@ public class ProjectsControllerTest : IClassFixture, IAsy return Task.CompletedTask; } - [Fact] - public async Task CreateProject_Success() + private async Task LoginAsync(string email) { + var tokens = await _factory.LoginAsync(email); + _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", tokens.Token); + } + + [Theory] + [InlineData(false, false)] + [InlineData(true, false)] + [InlineData(false, true)] + public async Task ListByOrganization_SmNotEnabled_NotFound(bool useSecrets, bool accessSecrets) + { + var (org, _) = await _organizationHelper.Initialize(useSecrets, accessSecrets); + await LoginAsync(_email); + + var response = await _client.GetAsync($"/organizations/{org.Id}/projects"); + Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); + } + + [Fact] + public async Task ListByOrganization_Success() + { + var (org, _) = await _organizationHelper.Initialize(true, true); + await LoginAsync(_email); + + var projectIds = new List(); + for (var i = 0; i < 3; i++) + { + var project = await _projectRepository.CreateAsync(new Project + { + OrganizationId = org.Id, + Name = _mockEncryptedString + }); + projectIds.Add(project.Id); + } + + var response = await _client.GetAsync($"/organizations/{org.Id}/projects"); + response.EnsureSuccessStatusCode(); + + var result = await response.Content.ReadFromJsonAsync>(); + Assert.NotNull(result); + Assert.NotEmpty(result!.Data); + Assert.Equal(projectIds.Count, result.Data.Count()); + } + + [Theory] + [InlineData(false, false)] + [InlineData(true, false)] + [InlineData(false, true)] + public async Task Create_SmNotEnabled_NotFound(bool useSecrets, bool accessSecrets) + { + var (org, _) = await _organizationHelper.Initialize(useSecrets, accessSecrets); + await LoginAsync(_email); + var request = new ProjectCreateRequestModel { Name = _mockEncryptedString }; - var response = await _client.PostAsJsonAsync($"/organizations/{_organization.Id}/projects", request); + var response = await _client.PostAsJsonAsync($"/organizations/{org.Id}/projects", request); + Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); + } + + [Fact] + public async Task Create_Success() + { + var (org, _) = await _organizationHelper.Initialize(true, true); + await LoginAsync(_email); + var request = new ProjectCreateRequestModel { Name = _mockEncryptedString }; + + var response = await _client.PostAsJsonAsync($"/organizations/{org.Id}/projects", request); response.EnsureSuccessStatusCode(); var result = await response.Content.ReadFromJsonAsync(); @@ -77,28 +128,43 @@ public class ProjectsControllerTest : IClassFixture, IAsy Assert.Null(createdProject.DeletedDate); } - [Fact] - public async Task CreateProject_NoPermission() + [Theory] + [InlineData(false, false)] + [InlineData(true, false)] + [InlineData(false, true)] + public async Task Update_SmNotEnabled_NotFound(bool useSecrets, bool accessSecrets) { - var request = new ProjectCreateRequestModel { Name = _mockEncryptedString }; + var (org, _) = await _organizationHelper.Initialize(useSecrets, accessSecrets); + await LoginAsync(_email); - var response = await _client.PostAsJsonAsync("/organizations/911d9106-7cf1-4d55-a3f9-f9abdeadecb3/projects", request); + var initialProject = await _projectRepository.CreateAsync(new Project + { + OrganizationId = org.Id, + Name = _mockEncryptedString + }); + var mockEncryptedString2 = "2.3Uk+WNBIoU5xzmVFNcoWzz==|1MsPIYuRfdOHfu/0uY6H2Q==|/98xy4wb6pHP1VTZ9JcNCYgQjEUMFPlqJgCwRk1YXKg="; + var request = new ProjectCreateRequestModel { Name = mockEncryptedString2 }; + + var response = await _client.PutAsJsonAsync($"/projects/{initialProject.Id}", request); Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); } [Fact] - public async Task UpdateProject_Success() + public async Task Update_Success() { + var (org, _) = await _organizationHelper.Initialize(true, true); + await LoginAsync(_email); + var initialProject = await _projectRepository.CreateAsync(new Project { - OrganizationId = _organization.Id, + OrganizationId = org.Id, Name = _mockEncryptedString }); var mockEncryptedString2 = "2.3Uk+WNBIoU5xzmVFNcoWzz==|1MsPIYuRfdOHfu/0uY6H2Q==|/98xy4wb6pHP1VTZ9JcNCYgQjEUMFPlqJgCwRk1YXKg="; - var request = new ProjectUpdateRequestModel() + var request = new ProjectUpdateRequestModel { Name = mockEncryptedString2 }; @@ -121,9 +187,12 @@ public class ProjectsControllerTest : IClassFixture, IAsy } [Fact] - public async Task UpdateProject_NotFound() + public async Task Update_NonExistingProject_Throws_NotFound() { - var request = new ProjectUpdateRequestModel() + await _organizationHelper.Initialize(true, true); + await LoginAsync(_email); + + var request = new ProjectUpdateRequestModel { Name = "2.3Uk+WNBIoU5xzmVFNcoWzz==|1MsPIYuRfdOHfu/0uY6H2Q==|/98xy4wb6pHP1VTZ9JcNCYgQjEUMFPlqJgCwRk1YXKg=", }; @@ -134,34 +203,59 @@ public class ProjectsControllerTest : IClassFixture, IAsy } [Fact] - public async Task UpdateProject_MissingPermission() + public async Task Update_MissingAccessPolicy_Throws_NotFound() { - // Create a new account as a user - await LoginAsNewOrgUser(); + var (org, _) = await _organizationHelper.Initialize(true, true); + var (email, _) = await _organizationHelper.CreateNewUser(OrganizationUserType.User, true); + await LoginAsync(email); var project = await _projectRepository.CreateAsync(new Project { - OrganizationId = _organization.Id, + OrganizationId = org.Id, Name = _mockEncryptedString }); - - var request = new ProjectUpdateRequestModel() + var request = new ProjectUpdateRequestModel { Name = "2.3Uk+WNBIoU5xzmVFNcoWzz==|1MsPIYuRfdOHfu/0uY6H2Q==|/98xy4wb6pHP1VTZ9JcNCYgQjEUMFPlqJgCwRk1YXKg=", }; var response = await _client.PutAsJsonAsync($"/projects/{project.Id}", request); - Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); + Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); + } + + [Theory] + [InlineData(false, false)] + [InlineData(true, false)] + [InlineData(false, true)] + public async Task Get_SmNotEnabled_NotFound(bool useSecrets, bool accessSecrets) + { + var (org, _) = await _organizationHelper.Initialize(useSecrets, accessSecrets); + await LoginAsync(_email); + + var project = await _projectRepository.CreateAsync(new Project + { + OrganizationId = org.Id, + Name = _mockEncryptedString + }); + + var mockEncryptedString2 = "2.3Uk+WNBIoU5xzmVFNcoWzz==|1MsPIYuRfdOHfu/0uY6H2Q==|/98xy4wb6pHP1VTZ9JcNCYgQjEUMFPlqJgCwRk1YXKg="; + var request = new ProjectCreateRequestModel { Name = mockEncryptedString2 }; + + var response = await _client.PutAsJsonAsync($"/projects/{project.Id}", request); + Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); } [Fact] - public async Task GetProject() + public async Task Get_Success() { + var (org, _) = await _organizationHelper.Initialize(true, true); + await LoginAsync(_email); + var createdProject = await _projectRepository.CreateAsync(new Project { - OrganizationId = _organization.Id, + OrganizationId = org.Id, Name = _mockEncryptedString }); @@ -174,39 +268,58 @@ public class ProjectsControllerTest : IClassFixture, IAsy } [Fact] - public async Task GetProjectsByOrganization() + public async Task Get_MissingAccessPolicy_Throws_NotFound() { - var projectsToCreate = 3; + var (org, _) = await _organizationHelper.Initialize(true, true); + var (email, _) = await _organizationHelper.CreateNewUser(OrganizationUserType.User, true); + await LoginAsync(email); + + var createdProject = await _projectRepository.CreateAsync(new Project + { + OrganizationId = org.Id, + Name = _mockEncryptedString + }); + + var response = await _client.GetAsync($"/projects/{createdProject.Id}"); + Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); + } + + [Theory] + [InlineData(false, false)] + [InlineData(true, false)] + [InlineData(false, true)] + public async Task Delete_SmNotEnabled_NotFound(bool useSecrets, bool accessSecrets) + { + var (org, _) = await _organizationHelper.Initialize(useSecrets, accessSecrets); + await LoginAsync(_email); + var projectIds = new List(); - for (var i = 0; i < projectsToCreate; i++) + for (var i = 0; i < 3; i++) { var project = await _projectRepository.CreateAsync(new Project { - OrganizationId = _organization.Id, - Name = _mockEncryptedString + OrganizationId = org.Id, + Name = _mockEncryptedString, }); projectIds.Add(project.Id); } - var response = await _client.GetAsync($"/organizations/{_organization.Id}/projects"); - response.EnsureSuccessStatusCode(); - - var result = await response.Content.ReadFromJsonAsync>(); - Assert.NotNull(result); - Assert.NotEmpty(result!.Data); - Assert.Equal(projectIds.Count, result.Data.Count()); + var response = await _client.PostAsync("/projects/delete", JsonContent.Create(projectIds)); + Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); } [Fact] - public async Task DeleteProjects() + public async Task Delete_Success() { - var projectsToDelete = 3; + var (org, _) = await _organizationHelper.Initialize(true, true); + await LoginAsync(_email); + var projectIds = new List(); - for (var i = 0; i < projectsToDelete; i++) + for (var i = 0; i < 3; i++) { var project = await _projectRepository.CreateAsync(new Project { - OrganizationId = _organization.Id, + OrganizationId = org.Id, Name = _mockEncryptedString, }); projectIds.Add(project.Id); diff --git a/test/Api.IntegrationTest/SecretsManager/Controllers/SecretsControllerTest.cs b/test/Api.IntegrationTest/SecretsManager/Controllers/SecretsControllerTest.cs index a93bd05fea..81ece16d3b 100644 --- a/test/Api.IntegrationTest/SecretsManager/Controllers/SecretsControllerTest.cs +++ b/test/Api.IntegrationTest/SecretsManager/Controllers/SecretsControllerTest.cs @@ -1,10 +1,9 @@ -using System.Net.Http.Headers; +using System.Net; +using System.Net.Http.Headers; using Bit.Api.IntegrationTest.Factories; -using Bit.Api.IntegrationTest.Helpers; using Bit.Api.Models.Response; using Bit.Api.SecretsManager.Models.Request; using Bit.Api.SecretsManager.Models.Response; -using Bit.Core.Entities; using Bit.Core.SecretsManager.Entities; using Bit.Core.SecretsManager.Repositories; using Bit.Test.Common.Helpers; @@ -21,7 +20,9 @@ public class SecretsControllerTest : IClassFixture, IAsyn private readonly ApiApplicationFactory _factory; private readonly ISecretRepository _secretRepository; private readonly IProjectRepository _projectRepository; - private Organization _organization = null!; + + private string _email = null!; + private SecretsManagerOrganizationHelper _organizationHelper = null!; public SecretsControllerTest(ApiApplicationFactory factory) { @@ -33,29 +34,98 @@ public class SecretsControllerTest : IClassFixture, IAsyn public async Task InitializeAsync() { - var ownerEmail = $"integration-test{Guid.NewGuid()}@bitwarden.com"; - var tokens = await _factory.LoginWithNewAccount(ownerEmail); - var (organization, _) = await OrganizationTestHelpers.SignUpAsync(_factory, ownerEmail: ownerEmail, billingEmail: ownerEmail); - _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", tokens.Token); - _organization = organization; + _email = $"integration-test{Guid.NewGuid()}@bitwarden.com"; + await _factory.LoginWithNewAccount(_email); + _organizationHelper = new SecretsManagerOrganizationHelper(_factory, _email); } public Task DisposeAsync() { + _client.Dispose(); return Task.CompletedTask; } - [Fact] - public async Task CreateSecret() + private async Task LoginAsync(string email) { - var request = new SecretCreateRequestModel() + var tokens = await _factory.LoginAsync(email); + _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", tokens.Token); + } + + [Theory] + [InlineData(false, false)] + [InlineData(true, false)] + [InlineData(false, true)] + public async Task ListByOrganization_SmNotEnabled_NotFound(bool useSecrets, bool accessSecrets) + { + var (org, _) = await _organizationHelper.Initialize(useSecrets, accessSecrets); + await LoginAsync(_email); + + var response = await _client.GetAsync($"/organizations/{org.Id}/secrets"); + Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); + } + + [Fact] + public async Task ListByOrganization_Owner_Success() + { + var (org, _) = await _organizationHelper.Initialize(true, true); + await LoginAsync(_email); + + var secretIds = new List(); + for (var i = 0; i < 3; i++) + { + var secret = await _secretRepository.CreateAsync(new Secret + { + OrganizationId = org.Id, + Key = _mockEncryptedString, + Value = _mockEncryptedString, + Note = _mockEncryptedString + }); + secretIds.Add(secret.Id); + } + + var response = await _client.GetAsync($"/organizations/{org.Id}/secrets"); + response.EnsureSuccessStatusCode(); + + var result = await response.Content.ReadFromJsonAsync(); + Assert.NotNull(result); + Assert.NotEmpty(result!.Secrets); + Assert.Equal(secretIds.Count, result.Secrets.Count()); + } + + [Theory] + [InlineData(false, false)] + [InlineData(true, false)] + [InlineData(false, true)] + public async Task Create_SmNotEnabled_NotFound(bool useSecrets, bool accessSecrets) + { + var (org, _) = await _organizationHelper.Initialize(useSecrets, accessSecrets); + await LoginAsync(_email); + + var request = new SecretCreateRequestModel { Key = _mockEncryptedString, Value = _mockEncryptedString, Note = _mockEncryptedString }; - var response = await _client.PostAsJsonAsync($"/organizations/{_organization.Id}/secrets", request); + var response = await _client.PostAsJsonAsync($"/organizations/{org.Id}/secrets", request); + Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); + } + + [Fact] + public async Task Create_Owner_Success() + { + var (org, _) = await _organizationHelper.Initialize(true, true); + await LoginAsync(_email); + + var request = new SecretCreateRequestModel + { + Key = _mockEncryptedString, + Value = _mockEncryptedString, + Note = _mockEncryptedString + }; + + var response = await _client.PostAsJsonAsync($"/organizations/{org.Id}/secrets", request); response.EnsureSuccessStatusCode(); var result = await response.Content.ReadFromJsonAsync(); @@ -77,23 +147,26 @@ public class SecretsControllerTest : IClassFixture, IAsyn } [Fact] - public async Task CreateSecretWithProject() + public async Task CreateWithProject_Owner_Success() { + var (org, _) = await _organizationHelper.Initialize(true, true); + await LoginAsync(_email); + var project = await _projectRepository.CreateAsync(new Project() { Id = new Guid(), - OrganizationId = _organization.Id, + OrganizationId = org.Id, Name = _mockEncryptedString }); - var projectIds = new[] { project.Id }; + var secretRequest = new SecretCreateRequestModel() { Key = _mockEncryptedString, Value = _mockEncryptedString, Note = _mockEncryptedString, - ProjectIds = projectIds, + ProjectIds = new[] { project.Id }, }; - var secretResponse = await _client.PostAsJsonAsync($"/organizations/{_organization.Id}/secrets", secretRequest); + var secretResponse = await _client.PostAsJsonAsync($"/organizations/{org.Id}/secrets", secretRequest); secretResponse.EnsureSuccessStatusCode(); var secretResult = await secretResponse.Content.ReadFromJsonAsync(); @@ -109,12 +182,88 @@ public class SecretsControllerTest : IClassFixture, IAsyn Assert.Equal(secret.RevisionDate, secretResult.RevisionDate); } - [Fact] - public async Task UpdateSecret() + [Theory] + [InlineData(false, false)] + [InlineData(true, false)] + [InlineData(false, true)] + public async Task Get_SmNotEnabled_NotFound(bool useSecrets, bool accessSecrets) { - var initialSecret = await _secretRepository.CreateAsync(new Secret + var (org, _) = await _organizationHelper.Initialize(useSecrets, accessSecrets); + await LoginAsync(_email); + + var secret = await _secretRepository.CreateAsync(new Secret { - OrganizationId = _organization.Id, + OrganizationId = org.Id, + Key = _mockEncryptedString, + Value = _mockEncryptedString, + Note = _mockEncryptedString + }); + + var response = await _client.GetAsync($"/organizations/secrets/{secret.Id}"); + Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); + } + + [Fact] + public async Task Get_Owner_Success() + { + var (org, _) = await _organizationHelper.Initialize(true, true); + await LoginAsync(_email); + + var secret = await _secretRepository.CreateAsync(new Secret + { + OrganizationId = org.Id, + Key = _mockEncryptedString, + Value = _mockEncryptedString, + Note = _mockEncryptedString + }); + + var response = await _client.GetAsync($"/secrets/{secret.Id}"); + response.EnsureSuccessStatusCode(); + var result = await response.Content.ReadFromJsonAsync(); + Assert.Equal(secret.Key, result!.Key); + Assert.Equal(secret.Value, result.Value); + Assert.Equal(secret.Note, result.Note); + Assert.Equal(secret.RevisionDate, result.RevisionDate); + Assert.Equal(secret.CreationDate, result.CreationDate); + } + + [Theory] + [InlineData(false, false)] + [InlineData(true, false)] + [InlineData(false, true)] + public async Task Update_SmNotEnabled_NotFound(bool useSecrets, bool accessSecrets) + { + var (org, _) = await _organizationHelper.Initialize(useSecrets, accessSecrets); + await LoginAsync(_email); + + var secret = await _secretRepository.CreateAsync(new Secret + { + OrganizationId = org.Id, + Key = _mockEncryptedString, + Value = _mockEncryptedString, + Note = _mockEncryptedString + }); + + var request = new SecretUpdateRequestModel + { + Key = _mockEncryptedString, + Value = "2.3Uk+WNBIoU5xzmVFNcoWzz==|1MsPIYuRfdOHfu/0uY6H2Q==|/98xy4wb6pHP1VTZ9JcNCYgQjEUMFPlqJgCwRk1YXKg=", + Note = _mockEncryptedString + }; + + var response = await _client.PutAsJsonAsync($"/organizations/secrets/{secret.Id}", request); + Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); + } + + [Fact] + public async Task Update_Owner_Success() + { + var (org, _) = await _organizationHelper.Initialize(true, true); + await LoginAsync(_email); + + var secret = await _secretRepository.CreateAsync(new Secret + { + OrganizationId = org.Id, Key = _mockEncryptedString, Value = _mockEncryptedString, Note = _mockEncryptedString @@ -127,15 +276,15 @@ public class SecretsControllerTest : IClassFixture, IAsyn Note = _mockEncryptedString }; - var response = await _client.PutAsJsonAsync($"/secrets/{initialSecret.Id}", request); + var response = await _client.PutAsJsonAsync($"/secrets/{secret.Id}", request); response.EnsureSuccessStatusCode(); var result = await response.Content.ReadFromJsonAsync(); Assert.Equal(request.Key, result!.Key); Assert.Equal(request.Value, result.Value); - Assert.NotEqual(initialSecret.Value, result.Value); + Assert.NotEqual(secret.Value, result.Value); Assert.Equal(request.Note, result.Note); AssertHelper.AssertRecent(result.RevisionDate); - Assert.NotEqual(initialSecret.RevisionDate, result.RevisionDate); + Assert.NotEqual(secret.RevisionDate, result.RevisionDate); var updatedSecret = await _secretRepository.GetByIdAsync(new Guid(result.Id)); Assert.NotNull(result); @@ -145,20 +294,44 @@ public class SecretsControllerTest : IClassFixture, IAsyn AssertHelper.AssertRecent(updatedSecret.RevisionDate); AssertHelper.AssertRecent(updatedSecret.CreationDate); Assert.Null(updatedSecret.DeletedDate); - Assert.NotEqual(initialSecret.Value, updatedSecret.Value); - Assert.NotEqual(initialSecret.RevisionDate, updatedSecret.RevisionDate); + Assert.NotEqual(secret.Value, updatedSecret.Value); + Assert.NotEqual(secret.RevisionDate, updatedSecret.RevisionDate); + } + + [Theory] + [InlineData(false, false)] + [InlineData(true, false)] + [InlineData(false, true)] + public async Task Delete_SmNotEnabled_NotFound(bool useSecrets, bool accessSecrets) + { + var (org, _) = await _organizationHelper.Initialize(useSecrets, accessSecrets); + await LoginAsync(_email); + + var secret = await _secretRepository.CreateAsync(new Secret + { + OrganizationId = org.Id, + Key = _mockEncryptedString, + Value = _mockEncryptedString, + Note = _mockEncryptedString + }); + var secretIds = new[] { secret.Id }; + + var response = await _client.PostAsJsonAsync("/secrets/delete", secretIds); + Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); } [Fact] - public async Task DeleteSecrets() + public async Task Delete_Owner_Success() { - var secretsToDelete = 3; + var (org, _) = await _organizationHelper.Initialize(true, true); + await LoginAsync(_email); + var secretIds = new List(); - for (var i = 0; i < secretsToDelete; i++) + for (var i = 0; i < 3; i++) { var secret = await _secretRepository.CreateAsync(new Secret { - OrganizationId = _organization.Id, + OrganizationId = org.Id, Key = _mockEncryptedString, Value = _mockEncryptedString, Note = _mockEncryptedString @@ -166,7 +339,7 @@ public class SecretsControllerTest : IClassFixture, IAsyn secretIds.Add(secret.Id); } - var response = await _client.PostAsync("/secrets/delete", JsonContent.Create(secretIds)); + var response = await _client.PostAsJsonAsync("/secrets/delete", secretIds); response.EnsureSuccessStatusCode(); var results = await response.Content.ReadFromJsonAsync>(); @@ -183,52 +356,4 @@ public class SecretsControllerTest : IClassFixture, IAsyn var secrets = await _secretRepository.GetManyByIds(secretIds); Assert.Empty(secrets); } - - [Fact] - public async Task GetSecret() - { - var createdSecret = await _secretRepository.CreateAsync(new Secret - { - OrganizationId = _organization.Id, - Key = _mockEncryptedString, - Value = _mockEncryptedString, - Note = _mockEncryptedString - }); - - - var response = await _client.GetAsync($"/secrets/{createdSecret.Id}"); - response.EnsureSuccessStatusCode(); - var result = await response.Content.ReadFromJsonAsync(); - Assert.Equal(createdSecret.Key, result!.Key); - Assert.Equal(createdSecret.Value, result.Value); - Assert.Equal(createdSecret.Note, result.Note); - Assert.Equal(createdSecret.RevisionDate, result.RevisionDate); - Assert.Equal(createdSecret.CreationDate, result.CreationDate); - } - - [Fact] - public async Task GetSecretsByOrganization() - { - var secretsToCreate = 3; - var secretIds = new List(); - for (var i = 0; i < secretsToCreate; i++) - { - var secret = await _secretRepository.CreateAsync(new Secret - { - OrganizationId = _organization.Id, - Key = _mockEncryptedString, - Value = _mockEncryptedString, - Note = _mockEncryptedString - }); - secretIds.Add(secret.Id); - } - - var response = await _client.GetAsync($"/organizations/{_organization.Id}/secrets"); - response.EnsureSuccessStatusCode(); - - var result = await response.Content.ReadFromJsonAsync(); - Assert.NotNull(result); - Assert.NotEmpty(result!.Secrets); - Assert.Equal(secretIds.Count, result.Secrets.Count()); - } } diff --git a/test/Api.IntegrationTest/SecretsManager/Controllers/ServiceAccountsControllerTests.cs b/test/Api.IntegrationTest/SecretsManager/Controllers/ServiceAccountsControllerTests.cs index 0de403137f..97373422d8 100644 --- a/test/Api.IntegrationTest/SecretsManager/Controllers/ServiceAccountsControllerTests.cs +++ b/test/Api.IntegrationTest/SecretsManager/Controllers/ServiceAccountsControllerTests.cs @@ -1,7 +1,6 @@ using System.Net; using System.Net.Http.Headers; using Bit.Api.IntegrationTest.Factories; -using Bit.Api.IntegrationTest.Helpers; using Bit.Api.Models.Response; using Bit.Api.SecretsManager.Models.Request; using Bit.Api.SecretsManager.Models.Response; @@ -26,8 +25,9 @@ public class ServiceAccountsControllerTest : IClassFixture Task.CompletedTask; + [Theory] + [InlineData(false, false)] + [InlineData(true, false)] + [InlineData(false, true)] + public async Task ListByOrganization_SmNotEnabled_NotFound(bool useSecrets, bool accessSecrets) + { + var (org, _) = await _organizationHelper.Initialize(useSecrets, accessSecrets); + await LoginAsync(_email); + + var response = await _client.GetAsync($"/organizations/{org.Id}/service-accounts"); + Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); + } [Fact] - public async Task GetServiceAccountsByOrganization_Admin() + public async Task ListByOrganization_Admin_Success() { - var serviceAccountIds = await SetupGetServiceAccountsByOrganizationAsync(); + var (org, _) = await _organizationHelper.Initialize(true, true); + await LoginAsync(_email); - var response = await _client.GetAsync($"/organizations/{_organization.Id}/service-accounts"); + var serviceAccountIds = await SetupGetServiceAccountsByOrganizationAsync(org); + + var response = await _client.GetAsync($"/organizations/{org.Id}/service-accounts"); response.EnsureSuccessStatusCode(); var result = await response.Content.ReadFromJsonAsync>(); @@ -64,56 +87,59 @@ public class ServiceAccountsControllerTest : IClassFixture new UserServiceAccountAccessPolicy { - OrganizationUserId = user.Id, + OrganizationUserId = orgUser.Id, GrantedServiceAccountId = id, Read = true, Write = false, }).Cast().ToList(); - await _accessPolicyRepository.CreateManyAsync(accessPolicies); - - var response = await _client.GetAsync($"/organizations/{_organization.Id}/service-accounts"); + var response = await _client.GetAsync($"/organizations/{org.Id}/service-accounts"); response.EnsureSuccessStatusCode(); var result = await response.Content.ReadFromJsonAsync>(); Assert.NotNull(result); Assert.NotEmpty(result!.Data); - Assert.Equal(serviceAccountIds.Count, result.Data.Count()); + Assert.Equal(2, result.Data.Count()); } - [Fact] - public async Task GetServiceAccountsByOrganization_User_NoPermission() + [Theory] + [InlineData(false, false)] + [InlineData(true, false)] + [InlineData(false, true)] + public async Task Create_SmNotEnabled_NotFound(bool useSecrets, bool accessSecrets) { - // Create a new account as a user - await LoginAsNewOrgUserAsync(); - await SetupGetServiceAccountsByOrganizationAsync(); + var (org, _) = await _organizationHelper.Initialize(useSecrets, accessSecrets); + await LoginAsync(_email); - var response = await _client.GetAsync($"/organizations/{_organization.Id}/service-accounts"); - response.EnsureSuccessStatusCode(); - var result = await response.Content.ReadFromJsonAsync>(); - - Assert.NotNull(result); - Assert.Empty(result!.Data); - } - - [Fact] - public async Task CreateServiceAccount_Admin() - { var request = new ServiceAccountCreateRequestModel { Name = _mockEncryptedString }; - var response = await _client.PostAsJsonAsync($"/organizations/{_organization.Id}/service-accounts", request); + var response = await _client.PostAsJsonAsync($"/organizations/{org.Id}/service-accounts", request); + Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); + } + + [Fact] + public async Task Create_Admin_Success() + { + var (org, _) = await _organizationHelper.Initialize(true, true); + await LoginAsync(_email); + + var request = new ServiceAccountCreateRequestModel { Name = _mockEncryptedString }; + + var response = await _client.PostAsJsonAsync($"/organizations/{org.Id}/service-accounts", request); response.EnsureSuccessStatusCode(); var result = await response.Content.ReadFromJsonAsync(); @@ -127,26 +153,47 @@ public class ServiceAccountsControllerTest : IClassFixture(); - - Assert.NotNull(result); - Assert.Equal(request.Name, result!.Name); - Assert.NotNull(result.ClientSecret); - Assert.Null(result.ExpireAt); - AssertHelper.AssertRecent(result.RevisionDate); - AssertHelper.AssertRecent(result.CreationDate); + await _accessPolicyRepository.CreateManyAsync(new List { policy }); } - [Fact] - public async Task CreateServiceAccountAccessTokenExpireAtNullAsync_User_NoPermission() + private async Task> SetupGetServiceAccountsByOrganizationAsync(Organization org) { - // Create a new account as a user - await LoginAsNewOrgUserAsync(); - - var serviceAccount = await _serviceAccountRepository.CreateAsync(new ServiceAccount - { - OrganizationId = _organization.Id, - Name = _mockEncryptedString, - }); - - var request = new AccessTokenCreateRequestModel - { - Name = _mockEncryptedString, - EncryptedPayload = _mockEncryptedString, - Key = _mockEncryptedString, - ExpireAt = null, - }; - - var response = await _client.PostAsJsonAsync($"/service-accounts/{serviceAccount.Id}/access-tokens", request); - Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); - } - - private async Task> SetupGetServiceAccountsByOrganizationAsync() - { - const int serviceAccountsToCreate = 3; var serviceAccountIds = new List(); - for (var i = 0; i < serviceAccountsToCreate; i++) + for (var i = 0; i < 3; i++) { var serviceAccount = await _serviceAccountRepository.CreateAsync(new ServiceAccount { - OrganizationId = _organization.Id, + OrganizationId = org.Id, Name = _mockEncryptedString, }); serviceAccountIds.Add(serviceAccount.Id); @@ -415,30 +453,4 @@ public class ServiceAccountsControllerTest : IClassFixture - { - new UserServiceAccountAccessPolicy - { - OrganizationUserId = userId, - GrantedServiceAccountId = serviceAccountId, - Read = read, - Write = write, - }, - }; - await _accessPolicyRepository.CreateManyAsync(accessPolicies); - } - - private async Task LoginAsNewOrgUserAsync(OrganizationUserType type = OrganizationUserType.User) - { - var email = $"integration-test{Guid.NewGuid()}@bitwarden.com"; - await _factory.LoginWithNewAccount(email); - var orgUser = await OrganizationTestHelpers.CreateUserAsync(_factory, _organization.Id, email, type); - var tokens = await _factory.LoginAsync(email); - _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", tokens.Token); - return orgUser; - } } diff --git a/test/Api.IntegrationTest/SecretsManager/SecretsManagerOrganizationHelper.cs b/test/Api.IntegrationTest/SecretsManager/SecretsManagerOrganizationHelper.cs new file mode 100644 index 0000000000..7e86386d27 --- /dev/null +++ b/test/Api.IntegrationTest/SecretsManager/SecretsManagerOrganizationHelper.cs @@ -0,0 +1,55 @@ +using Bit.Api.IntegrationTest.Factories; +using Bit.Api.IntegrationTest.Helpers; +using Bit.Core.Entities; +using Bit.Core.Enums; +using Bit.Core.Repositories; + +namespace Bit.Api.IntegrationTest.SecretsManager; + +public class SecretsManagerOrganizationHelper +{ + private readonly ApiApplicationFactory _factory; + private readonly string _ownerEmail; + private readonly IOrganizationRepository _organizationRepository; + private readonly IOrganizationUserRepository _organizationUserRepository; + + public Organization _organization = null!; + public OrganizationUser _owner = null!; + + public SecretsManagerOrganizationHelper(ApiApplicationFactory factory, string ownerEmail) + { + _factory = factory; + _organizationRepository = factory.GetService(); + _organizationUserRepository = factory.GetService(); + + _ownerEmail = ownerEmail; + } + + public async Task<(Organization organization, OrganizationUser owner)> Initialize(bool useSecrets, bool ownerAccessSecrets) + { + (_organization, _owner) = await OrganizationTestHelpers.SignUpAsync(_factory, ownerEmail: _ownerEmail, billingEmail: _ownerEmail); + + if (useSecrets) + { + _organization.UseSecretsManager = true; + await _organizationRepository.ReplaceAsync(_organization); + } + + if (ownerAccessSecrets) + { + _owner.AccessSecretsManager = ownerAccessSecrets; + await _organizationUserRepository.ReplaceAsync(_owner); + } + + return (_organization, _owner); + } + + public async Task<(string email, OrganizationUser orgUser)> CreateNewUser(OrganizationUserType userType, bool accessSecrets) + { + var email = $"integration-test{Guid.NewGuid()}@bitwarden.com"; + await _factory.LoginWithNewAccount(email); + var orgUser = await OrganizationTestHelpers.CreateUserAsync(_factory, _organization.Id, email, userType, accessSecrets); + + return (email, orgUser); + } +} diff --git a/test/Api.Test/Controllers/OrganizationConnectionsControllerTests.cs b/test/Api.Test/Controllers/OrganizationConnectionsControllerTests.cs index 594e708bdf..0f243b9efb 100644 --- a/test/Api.Test/Controllers/OrganizationConnectionsControllerTests.cs +++ b/test/Api.Test/Controllers/OrganizationConnectionsControllerTests.cs @@ -366,7 +366,7 @@ public class OrganizationConnectionsControllerTests } private static OrganizationConnectionRequestModel RequestModelFromEntity(OrganizationConnection entity) - where T : new() + where T : IConnectionConfig { return new(new OrganizationConnectionRequestModel() { diff --git a/test/Api.Test/Controllers/OrganizationsControllerTests.cs b/test/Api.Test/Controllers/OrganizationsControllerTests.cs index fa1855c70d..f056beea80 100644 --- a/test/Api.Test/Controllers/OrganizationsControllerTests.cs +++ b/test/Api.Test/Controllers/OrganizationsControllerTests.cs @@ -6,6 +6,7 @@ using Bit.Core.Entities; using Bit.Core.Exceptions; using Bit.Core.Models.Data; using Bit.Core.OrganizationFeatures.OrganizationApiKeys.Interfaces; +using Bit.Core.OrganizationFeatures.OrganizationLicenses.Interfaces; using Bit.Core.Repositories; using Bit.Core.Services; using Bit.Core.Settings; @@ -29,6 +30,7 @@ public class OrganizationsControllerTests : IDisposable private readonly IGetOrganizationApiKeyQuery _getOrganizationApiKeyQuery; private readonly IRotateOrganizationApiKeyCommand _rotateOrganizationApiKeyCommand; private readonly IOrganizationApiKeyRepository _organizationApiKeyRepository; + private readonly ICloudGetOrganizationLicenseQuery _cloudGetOrganizationLicenseQuery; private readonly ICreateOrganizationApiKeyCommand _createOrganizationApiKeyCommand; private readonly OrganizationsController _sut; @@ -48,12 +50,13 @@ public class OrganizationsControllerTests : IDisposable _rotateOrganizationApiKeyCommand = Substitute.For(); _organizationApiKeyRepository = Substitute.For(); _userService = Substitute.For(); + _cloudGetOrganizationLicenseQuery = Substitute.For(); _createOrganizationApiKeyCommand = Substitute.For(); _sut = new OrganizationsController(_organizationRepository, _organizationUserRepository, _policyRepository, _organizationService, _userService, _paymentService, _currentContext, _ssoConfigRepository, _ssoConfigService, _getOrganizationApiKeyQuery, _rotateOrganizationApiKeyCommand, - _createOrganizationApiKeyCommand, _organizationApiKeyRepository, _globalSettings); + _createOrganizationApiKeyCommand, _organizationApiKeyRepository, _cloudGetOrganizationLicenseQuery, _globalSettings); } public void Dispose() diff --git a/test/Api.Test/Controllers/SyncControllerTests.cs b/test/Api.Test/Controllers/SyncControllerTests.cs new file mode 100644 index 0000000000..0b48af7fe1 --- /dev/null +++ b/test/Api.Test/Controllers/SyncControllerTests.cs @@ -0,0 +1,358 @@ +using System.Security.Claims; +using System.Text.Json; +using AutoFixture; +using Bit.Api.Controllers; +using Bit.Api.Models.Response; +using Bit.Core.Entities; +using Bit.Core.Enums; +using Bit.Core.Enums.Provider; +using Bit.Core.Exceptions; +using Bit.Core.Models.Data; +using Bit.Core.Models.Data.Organizations.OrganizationUsers; +using Bit.Core.Repositories; +using Bit.Core.Services; +using Bit.Core.Utilities; +using Bit.Test.Common.AutoFixture; +using Bit.Test.Common.AutoFixture.Attributes; +using Core.Models.Data; +using NSubstitute; +using NSubstitute.ReturnsExtensions; +using Xunit; + +namespace Bit.Api.Test.Controllers; + +[ControllerCustomize(typeof(SyncController))] +[SutProviderCustomize] +public class SyncControllerTests +{ + [Theory] + [BitAutoData] + public async Task Get_ThrowBadRequest_WhenUserNotFound(SutProvider sutProvider) + { + sutProvider.GetDependency().GetUserByPrincipalAsync(Arg.Any()).ReturnsNull(); + + async Task GetAction() + { + return await sutProvider.Sut.Get(); + } + + await Assert.ThrowsAsync((Func>)GetAction); + } + + [Theory] + [BitAutoData] + public async Task Get_Success_AtLeastOneEnabledOrg(User user, + List> userEquivalentDomains, + List userExcludedGlobalEquivalentDomains, + ICollection organizationUserDetails, + ICollection providerUserDetails, + IEnumerable providerUserOrganizationDetails, + ICollection folders, + ICollection ciphers, + ICollection sends, + ICollection policies, + ICollection collections, + SutProvider sutProvider) + { + // Get dependencies + var userService = sutProvider.GetDependency(); + var organizationUserRepository = sutProvider.GetDependency(); + var providerUserRepository = sutProvider.GetDependency(); + var folderRepository = sutProvider.GetDependency(); + var cipherRepository = sutProvider.GetDependency(); + var sendRepository = sutProvider.GetDependency(); + var policyRepository = sutProvider.GetDependency(); + var collectionRepository = sutProvider.GetDependency(); + var collectionCipherRepository = sutProvider.GetDependency(); + + // Adjust random data to match required formats / test intentions + user.EquivalentDomains = JsonSerializer.Serialize(userEquivalentDomains); + user.ExcludedGlobalEquivalentDomains = JsonSerializer.Serialize(userExcludedGlobalEquivalentDomains); + + // At least 1 org needs to be enabled to fully test + if (!organizationUserDetails.Any(o => o.Enabled)) + { + // We need at least 1 enabled org + if (organizationUserDetails.Count > 0) + { + organizationUserDetails.First().Enabled = true; + } + else + { + // create an enabled org + var enabledOrg = new Fixture().Create(); + enabledOrg.Enabled = true; + organizationUserDetails.Add((enabledOrg)); + } + } + + // Setup returns + userService.GetUserByPrincipalAsync(Arg.Any()).ReturnsForAnyArgs(user); + + organizationUserRepository + .GetManyDetailsByUserAsync(user.Id, OrganizationUserStatusType.Confirmed).Returns(organizationUserDetails); + + providerUserRepository + .GetManyDetailsByUserAsync(user.Id, ProviderUserStatusType.Confirmed).Returns(providerUserDetails); + + providerUserRepository + .GetManyOrganizationDetailsByUserAsync(user.Id, ProviderUserStatusType.Confirmed) + .Returns(providerUserOrganizationDetails); + + folderRepository.GetManyByUserIdAsync(user.Id).Returns(folders); + cipherRepository.GetManyByUserIdAsync(user.Id).Returns(ciphers); + + sendRepository + .GetManyByUserIdAsync(user.Id).Returns(sends); + + policyRepository.GetManyByUserIdAsync(user.Id).Returns(policies); + + // Returns for methods only called if we have enabled orgs + collectionRepository.GetManyByUserIdAsync(user.Id).Returns(collections); + collectionCipherRepository.GetManyByUserIdAsync(user.Id).Returns(new List()); + + // Back to standard test setup + userService.TwoFactorIsEnabledAsync(user).Returns(false); + userService.HasPremiumFromOrganization(user).Returns(false); + + // Execute GET + var result = await sutProvider.Sut.Get(); + + + // Asserts + // Assert that methods are called + var hasEnabledOrgs = organizationUserDetails.Any(o => o.Enabled); + this.AssertMethodsCalledAsync(userService, organizationUserRepository, providerUserRepository, folderRepository, + cipherRepository, sendRepository, collectionRepository, collectionCipherRepository, hasEnabledOrgs); + + Assert.IsType(result); + + // Collections should not be empty when at least 1 org is enabled + Assert.NotEmpty(result.Collections); + } + + + [Theory] + [BitAutoData] + public async Task Get_Success_AllDisabledOrgs(User user, + List> userEquivalentDomains, + List userExcludedGlobalEquivalentDomains, + ICollection organizationUserDetails, + ICollection providerUserDetails, + IEnumerable providerUserOrganizationDetails, + ICollection folders, + ICollection ciphers, + ICollection sends, + ICollection policies, + SutProvider sutProvider) + { + // Get dependencies + var userService = sutProvider.GetDependency(); + var organizationUserRepository = sutProvider.GetDependency(); + var providerUserRepository = sutProvider.GetDependency(); + var folderRepository = sutProvider.GetDependency(); + var cipherRepository = sutProvider.GetDependency(); + var sendRepository = sutProvider.GetDependency(); + var policyRepository = sutProvider.GetDependency(); + var collectionRepository = sutProvider.GetDependency(); + var collectionCipherRepository = sutProvider.GetDependency(); + + // Adjust random data to match required formats / test intentions + user.EquivalentDomains = JsonSerializer.Serialize(userEquivalentDomains); + user.ExcludedGlobalEquivalentDomains = JsonSerializer.Serialize(userExcludedGlobalEquivalentDomains); + + // All orgs disabled + if (organizationUserDetails.Count > 0) + { + foreach (var orgUserDetails in organizationUserDetails) + { + orgUserDetails.Enabled = false; + } + } + else + { + var disabledOrg = new Fixture().Create(); + disabledOrg.Enabled = false; + organizationUserDetails.Add((disabledOrg)); + } + + + // Setup returns + userService.GetUserByPrincipalAsync(Arg.Any()).ReturnsForAnyArgs(user); + + organizationUserRepository + .GetManyDetailsByUserAsync(user.Id, OrganizationUserStatusType.Confirmed).Returns(organizationUserDetails); + + providerUserRepository + .GetManyDetailsByUserAsync(user.Id, ProviderUserStatusType.Confirmed).Returns(providerUserDetails); + + providerUserRepository + .GetManyOrganizationDetailsByUserAsync(user.Id, ProviderUserStatusType.Confirmed) + .Returns(providerUserOrganizationDetails); + + folderRepository.GetManyByUserIdAsync(user.Id).Returns(folders); + cipherRepository.GetManyByUserIdAsync(user.Id).Returns(ciphers); + + sendRepository + .GetManyByUserIdAsync(user.Id).Returns(sends); + + policyRepository.GetManyByUserIdAsync(user.Id).Returns(policies); + + userService.TwoFactorIsEnabledAsync(user).Returns(false); + userService.HasPremiumFromOrganization(user).Returns(false); + + // Execute GET + var result = await sutProvider.Sut.Get(); + + + // Asserts + // Assert that methods are called + + var hasEnabledOrgs = organizationUserDetails.Any(o => o.Enabled); + this.AssertMethodsCalledAsync(userService, organizationUserRepository, providerUserRepository, folderRepository, + cipherRepository, sendRepository, collectionRepository, collectionCipherRepository, hasEnabledOrgs); + + Assert.IsType(result); + + // Collections should be empty when all standard orgs are disabled. + Assert.Empty(result.Collections); + } + + + // Test where provider org has specific plan type and assert plan type comes out on SyncResponseModel class on ProfileResponseModel + [Theory] + [BitAutoData] + public async Task Get_ProviderPlanTypeProperlyPopulated(User user, + List> userEquivalentDomains, + List userExcludedGlobalEquivalentDomains, + ICollection organizationUserDetails, + ICollection providerUserDetails, + IEnumerable providerUserOrganizationDetails, + ICollection folders, + ICollection ciphers, + ICollection sends, + ICollection policies, + ICollection collections, + SutProvider sutProvider) + { + // Get dependencies + var userService = sutProvider.GetDependency(); + var organizationUserRepository = sutProvider.GetDependency(); + var providerUserRepository = sutProvider.GetDependency(); + var folderRepository = sutProvider.GetDependency(); + var cipherRepository = sutProvider.GetDependency(); + var sendRepository = sutProvider.GetDependency(); + var policyRepository = sutProvider.GetDependency(); + var collectionRepository = sutProvider.GetDependency(); + var collectionCipherRepository = sutProvider.GetDependency(); + + // Adjust random data to match required formats / test intentions + user.EquivalentDomains = JsonSerializer.Serialize(userEquivalentDomains); + user.ExcludedGlobalEquivalentDomains = JsonSerializer.Serialize(userExcludedGlobalEquivalentDomains); + + + // Setup returns + userService.GetUserByPrincipalAsync(Arg.Any()).ReturnsForAnyArgs(user); + + organizationUserRepository + .GetManyDetailsByUserAsync(user.Id, OrganizationUserStatusType.Confirmed).Returns(organizationUserDetails); + + providerUserRepository + .GetManyDetailsByUserAsync(user.Id, ProviderUserStatusType.Confirmed).Returns(providerUserDetails); + + providerUserRepository + .GetManyOrganizationDetailsByUserAsync(user.Id, ProviderUserStatusType.Confirmed) + .Returns(providerUserOrganizationDetails); + + folderRepository.GetManyByUserIdAsync(user.Id).Returns(folders); + cipherRepository.GetManyByUserIdAsync(user.Id).Returns(ciphers); + + sendRepository + .GetManyByUserIdAsync(user.Id).Returns(sends); + + policyRepository.GetManyByUserIdAsync(user.Id).Returns(policies); + + // Returns for methods only called if we have enabled orgs + collectionRepository.GetManyByUserIdAsync(user.Id).Returns(collections); + collectionCipherRepository.GetManyByUserIdAsync(user.Id).Returns(new List()); + + // Back to standard test setup + userService.TwoFactorIsEnabledAsync(user).Returns(false); + userService.HasPremiumFromOrganization(user).Returns(false); + + // Execute GET + var result = await sutProvider.Sut.Get(); + + // Asserts + // Assert that methods are called + + var hasEnabledOrgs = organizationUserDetails.Any(o => o.Enabled); + this.AssertMethodsCalledAsync(userService, organizationUserRepository, providerUserRepository, folderRepository, + cipherRepository, sendRepository, collectionRepository, collectionCipherRepository, hasEnabledOrgs); + + Assert.IsType(result); + + // Look up ProviderOrg output and compare to ProviderOrg method inputs to ensure + // product type is set correctly. + foreach (var profProviderOrg in result.Profile.ProviderOrganizations) + { + var matchedProviderUserOrgDetails = + providerUserOrganizationDetails.FirstOrDefault(p => p.OrganizationId.ToString() == profProviderOrg.Id); + + if (matchedProviderUserOrgDetails != null) + { + var providerOrgProductType = StaticStore.GetPlan(matchedProviderUserOrgDetails.PlanType).Product; + Assert.Equal(providerOrgProductType, profProviderOrg.PlanProductType); + } + } + } + + + private async void AssertMethodsCalledAsync(IUserService userService, + IOrganizationUserRepository organizationUserRepository, + IProviderUserRepository providerUserRepository, IFolderRepository folderRepository, + ICipherRepository cipherRepository, ISendRepository sendRepository, + ICollectionRepository collectionRepository, + ICollectionCipherRepository collectionCipherRepository, + bool hasEnabledOrgs) + { + await userService.ReceivedWithAnyArgs(1).GetUserByPrincipalAsync(default); + await organizationUserRepository.ReceivedWithAnyArgs(1) + .GetManyDetailsByUserAsync(default); + await providerUserRepository.ReceivedWithAnyArgs(1) + .GetManyDetailsByUserAsync(default); + await providerUserRepository.ReceivedWithAnyArgs(1) + .GetManyOrganizationDetailsByUserAsync(default); + + await folderRepository.ReceivedWithAnyArgs(1) + .GetManyByUserIdAsync(default); + + await cipherRepository.ReceivedWithAnyArgs(1) + .GetManyByUserIdAsync(default); + + await sendRepository.ReceivedWithAnyArgs(1) + .GetManyByUserIdAsync(default); + + // These two are only called when at least 1 enabled org. + if (hasEnabledOrgs) + { + await collectionRepository.ReceivedWithAnyArgs(1) + .GetManyByUserIdAsync(default); + await collectionCipherRepository.ReceivedWithAnyArgs(1) + .GetManyByUserIdAsync(default); + } + else + { + // all disabled orgs + await collectionRepository.ReceivedWithAnyArgs(0) + .GetManyByUserIdAsync(default); + await collectionCipherRepository.ReceivedWithAnyArgs(0) + .GetManyByUserIdAsync(default); + } + + await userService.ReceivedWithAnyArgs(1) + .TwoFactorIsEnabledAsync(default); + await userService.ReceivedWithAnyArgs(1) + .HasPremiumFromOrganization(default); + } +} diff --git a/test/Api.Test/SecretsManager/Controllers/AccessPoliciesControllerTests.cs b/test/Api.Test/SecretsManager/Controllers/AccessPoliciesControllerTests.cs index 644f6a1701..1a12a5a7e2 100644 --- a/test/Api.Test/SecretsManager/Controllers/AccessPoliciesControllerTests.cs +++ b/test/Api.Test/SecretsManager/Controllers/AccessPoliciesControllerTests.cs @@ -25,7 +25,7 @@ public class AccessPoliciesControllerTests var result = await sutProvider.Sut.GetProjectAccessPoliciesAsync(id); await sutProvider.GetDependency().Received(1) - .GetManyByProjectId(Arg.Is(AssertHelper.AssertPropertyEqual(id))); + .GetManyByGrantedProjectIdAsync(Arg.Is(AssertHelper.AssertPropertyEqual(id))); Assert.Empty(result.GroupAccessPolicies); Assert.Empty(result.UserAccessPolicies); @@ -37,13 +37,13 @@ public class AccessPoliciesControllerTests public async void GetAccessPoliciesByProject_Success(SutProvider sutProvider, Guid id, UserProjectAccessPolicy resultAccessPolicy) { - sutProvider.GetDependency().GetManyByProjectId(default) + sutProvider.GetDependency().GetManyByGrantedProjectIdAsync(default) .ReturnsForAnyArgs(new List { resultAccessPolicy }); var result = await sutProvider.Sut.GetProjectAccessPoliciesAsync(id); await sutProvider.GetDependency().Received(1) - .GetManyByProjectId(Arg.Is(AssertHelper.AssertPropertyEqual(id))); + .GetManyByGrantedProjectIdAsync(Arg.Is(AssertHelper.AssertPropertyEqual(id))); Assert.Empty(result.GroupAccessPolicies); Assert.NotEmpty(result.UserAccessPolicies); diff --git a/test/Api.Test/SecretsManager/Controllers/ProjectsControllerTests.cs b/test/Api.Test/SecretsManager/Controllers/ProjectsControllerTests.cs index 1a83fd5c79..747d213269 100644 --- a/test/Api.Test/SecretsManager/Controllers/ProjectsControllerTests.cs +++ b/test/Api.Test/SecretsManager/Controllers/ProjectsControllerTests.cs @@ -29,7 +29,7 @@ public class ProjectsControllerTests } sutProvider.GetDependency().DeleteProjects(ids, default).ReturnsForAnyArgs(mockResult); - var results = await sutProvider.Sut.BulkDeleteProjectsAsync(ids); + var results = await sutProvider.Sut.BulkDeleteAsync(ids); await sutProvider.GetDependency().Received(1) .DeleteProjects(Arg.Is(ids), Arg.Any()); Assert.Equal(data.Count, results.Data.Count()); @@ -40,6 +40,6 @@ public class ProjectsControllerTests public async void BulkDeleteProjects_NoGuids_ThrowsArgumentNullException(SutProvider sutProvider) { sutProvider.GetDependency().GetProperUserId(default).ReturnsForAnyArgs(Guid.NewGuid()); - await Assert.ThrowsAsync(() => sutProvider.Sut.BulkDeleteProjectsAsync(new List())); + await Assert.ThrowsAsync(() => sutProvider.Sut.BulkDeleteAsync(new List())); } } diff --git a/test/Api.Test/SecretsManager/Controllers/SecretsControllerTests.cs b/test/Api.Test/SecretsManager/Controllers/SecretsControllerTests.cs index f8454dfa1b..aff105abed 100644 --- a/test/Api.Test/SecretsManager/Controllers/SecretsControllerTests.cs +++ b/test/Api.Test/SecretsManager/Controllers/SecretsControllerTests.cs @@ -1,5 +1,6 @@ using Bit.Api.SecretsManager.Controllers; using Bit.Api.SecretsManager.Models.Request; +using Bit.Core.Context; using Bit.Core.Exceptions; using Bit.Core.SecretsManager.Commands.Secrets.Interfaces; using Bit.Core.SecretsManager.Entities; @@ -23,7 +24,8 @@ public class SecretsControllerTests [BitAutoData] public async void GetSecretsByOrganization_ReturnsEmptyList(SutProvider sutProvider, Guid id) { - var result = await sutProvider.Sut.GetSecretsByOrganizationAsync(id); + sutProvider.GetDependency().AccessSecretsManager(id).Returns(true); + var result = await sutProvider.Sut.ListByOrganizationAsync(id); await sutProvider.GetDependency().Received(1) .GetManyByOrganizationIdAsync(Arg.Is(AssertHelper.AssertPropertyEqual(id))); @@ -31,11 +33,34 @@ public class SecretsControllerTests Assert.Empty(result.Secrets); } + [Theory] + [BitAutoData] + public async void GetSecretsByOrganization_Success(SutProvider sutProvider, Secret resultSecret) + { + sutProvider.GetDependency().AccessSecretsManager(default).ReturnsForAnyArgs(true); + sutProvider.GetDependency().GetManyByOrganizationIdAsync(default).ReturnsForAnyArgs(new List { resultSecret }); + + var result = await sutProvider.Sut.ListByOrganizationAsync(resultSecret.OrganizationId); + + await sutProvider.GetDependency().Received(1) + .GetManyByOrganizationIdAsync(Arg.Is(AssertHelper.AssertPropertyEqual(resultSecret.OrganizationId))); + } + + [Theory] + [BitAutoData] + public async void GetSecretsByOrganization_AccessDenied_Throws(SutProvider sutProvider, Secret resultSecret) + { + sutProvider.GetDependency().AccessSecretsManager(default).ReturnsForAnyArgs(false); + + await Assert.ThrowsAsync(() => + sutProvider.Sut.ListByOrganizationAsync(resultSecret.OrganizationId)); + } + [Theory] [BitAutoData] public async void GetSecret_NotFound(SutProvider sutProvider) { - await Assert.ThrowsAsync(() => sutProvider.Sut.GetSecretAsync(Guid.NewGuid())); + await Assert.ThrowsAsync(() => sutProvider.Sut.GetAsync(Guid.NewGuid())); } [Theory] @@ -44,33 +69,22 @@ public class SecretsControllerTests { sutProvider.GetDependency().GetByIdAsync(default).ReturnsForAnyArgs(resultSecret); - var result = await sutProvider.Sut.GetSecretAsync(resultSecret.Id); + var result = await sutProvider.Sut.GetAsync(resultSecret.Id); await sutProvider.GetDependency().Received(1) .GetByIdAsync(Arg.Is(AssertHelper.AssertPropertyEqual(resultSecret.Id))); } - [Theory] - [BitAutoData] - public async void GetSecretsByOrganization_Success(SutProvider sutProvider, Secret resultSecret) - { - sutProvider.GetDependency().GetManyByOrganizationIdAsync(default).ReturnsForAnyArgs(new List() { resultSecret }); - - var result = await sutProvider.Sut.GetSecretsByOrganizationAsync(resultSecret.OrganizationId); - - await sutProvider.GetDependency().Received(1) - .GetManyByOrganizationIdAsync(Arg.Is(AssertHelper.AssertPropertyEqual(resultSecret.OrganizationId))); - } - [Theory] [BitAutoData] public async void CreateSecret_Success(SutProvider sutProvider, SecretCreateRequestModel data, Guid organizationId) { var resultSecret = data.ToSecret(organizationId); + sutProvider.GetDependency().AccessSecretsManager(organizationId).Returns(true); sutProvider.GetDependency().CreateAsync(default).ReturnsForAnyArgs(resultSecret); - var result = await sutProvider.Sut.CreateSecretAsync(organizationId, data); + var result = await sutProvider.Sut.CreateAsync(organizationId, data); await sutProvider.GetDependency().Received(1) .CreateAsync(Arg.Any()); } @@ -82,7 +96,7 @@ public class SecretsControllerTests var resultSecret = data.ToSecret(secretId); sutProvider.GetDependency().UpdateAsync(default).ReturnsForAnyArgs(resultSecret); - var result = await sutProvider.Sut.UpdateSecretAsync(secretId, data); + var result = await sutProvider.Sut.UpdateAsync(secretId, data); await sutProvider.GetDependency().Received(1) .UpdateAsync(Arg.Any()); } diff --git a/test/Api.Test/SecretsManager/Controllers/ServiceAccountsControllerTests.cs b/test/Api.Test/SecretsManager/Controllers/ServiceAccountsControllerTests.cs index 2cbe18df7e..c6b80b1832 100644 --- a/test/Api.Test/SecretsManager/Controllers/ServiceAccountsControllerTests.cs +++ b/test/Api.Test/SecretsManager/Controllers/ServiceAccountsControllerTests.cs @@ -26,8 +26,9 @@ public class ServiceAccountsControllerTests [BitAutoData] public async void GetServiceAccountsByOrganization_ReturnsEmptyList(SutProvider sutProvider, Guid id) { + sutProvider.GetDependency().AccessSecretsManager(id).Returns(true); sutProvider.GetDependency().GetProperUserId(default).ReturnsForAnyArgs(Guid.NewGuid()); - var result = await sutProvider.Sut.GetServiceAccountsByOrganizationAsync(id); + var result = await sutProvider.Sut.ListByOrganizationAsync(id); await sutProvider.GetDependency().Received(1) .GetManyByOrganizationIdAsync(Arg.Is(AssertHelper.AssertPropertyEqual(id)), Arg.Any(), Arg.Any()); @@ -39,10 +40,11 @@ public class ServiceAccountsControllerTests [BitAutoData] public async void GetServiceAccountsByOrganization_Success(SutProvider sutProvider, ServiceAccount resultServiceAccount) { + sutProvider.GetDependency().AccessSecretsManager(default).ReturnsForAnyArgs(true); sutProvider.GetDependency().GetProperUserId(default).ReturnsForAnyArgs(Guid.NewGuid()); sutProvider.GetDependency().GetManyByOrganizationIdAsync(default, default, default).ReturnsForAnyArgs(new List() { resultServiceAccount }); - var result = await sutProvider.Sut.GetServiceAccountsByOrganizationAsync(resultServiceAccount.OrganizationId); + var result = await sutProvider.Sut.ListByOrganizationAsync(resultServiceAccount.OrganizationId); await sutProvider.GetDependency().Received(1) .GetManyByOrganizationIdAsync(Arg.Is(AssertHelper.AssertPropertyEqual(resultServiceAccount.OrganizationId)), Arg.Any(), Arg.Any()); @@ -50,18 +52,29 @@ public class ServiceAccountsControllerTests Assert.Single(result.Data); } + [Theory] + [BitAutoData] + public async void GetServiceAccountsByOrganization_AccessDenied_Throws(SutProvider sutProvider, Guid orgId) + { + sutProvider.GetDependency().AccessSecretsManager(default).ReturnsForAnyArgs(false); + + await Assert.ThrowsAsync(() => + sutProvider.Sut.ListByOrganizationAsync(orgId)); + } [Theory] [BitAutoData] public async void CreateServiceAccount_Success(SutProvider sutProvider, ServiceAccountCreateRequestModel data, Guid organizationId) { + sutProvider.GetDependency().GetProperUserId(default).ReturnsForAnyArgs(Guid.NewGuid()); + sutProvider.GetDependency().AccessSecretsManager(organizationId).Returns(true); sutProvider.GetDependency().OrganizationUser(default).ReturnsForAnyArgs(true); var resultServiceAccount = data.ToServiceAccount(organizationId); - sutProvider.GetDependency().CreateAsync(default).ReturnsForAnyArgs(resultServiceAccount); + sutProvider.GetDependency().CreateAsync(default, default).ReturnsForAnyArgs(resultServiceAccount); - var result = await sutProvider.Sut.CreateServiceAccountAsync(organizationId, data); + await sutProvider.Sut.CreateAsync(organizationId, data); await sutProvider.GetDependency().Received(1) - .CreateAsync(Arg.Any()); + .CreateAsync(Arg.Any(), Arg.Any()); } [Theory] @@ -70,11 +83,13 @@ public class ServiceAccountsControllerTests { sutProvider.GetDependency().OrganizationUser(default).ReturnsForAnyArgs(false); var resultServiceAccount = data.ToServiceAccount(organizationId); - sutProvider.GetDependency().CreateAsync(default).ReturnsForAnyArgs(resultServiceAccount); + sutProvider.GetDependency().CreateAsync(default, default).ReturnsForAnyArgs(resultServiceAccount); - await Assert.ThrowsAsync(() => sutProvider.Sut.CreateServiceAccountAsync(organizationId, data)); + await Assert.ThrowsAsync(() => sutProvider.Sut.CreateAsync(organizationId, data)); - await sutProvider.GetDependency().DidNotReceiveWithAnyArgs().CreateAsync(Arg.Any()); + await sutProvider.GetDependency() + .DidNotReceiveWithAnyArgs() + .CreateAsync(Arg.Any(), Arg.Any()); } [Theory] @@ -85,7 +100,7 @@ public class ServiceAccountsControllerTests var resultServiceAccount = data.ToServiceAccount(serviceAccountId); sutProvider.GetDependency().UpdateAsync(default, default).ReturnsForAnyArgs(resultServiceAccount); - var result = await sutProvider.Sut.UpdateServiceAccountAsync(serviceAccountId, data); + var result = await sutProvider.Sut.UpdateAsync(serviceAccountId, data); await sutProvider.GetDependency().Received(1) .UpdateAsync(Arg.Any(), Arg.Any()); } @@ -121,6 +136,7 @@ public class ServiceAccountsControllerTests public async void GetAccessTokens_Admin_Success(SutProvider sutProvider, ServiceAccount data, Guid userId, ICollection resultApiKeys) { sutProvider.GetDependency().GetProperUserId(default).ReturnsForAnyArgs(userId); + sutProvider.GetDependency().AccessSecretsManager(data.OrganizationId).Returns(true); sutProvider.GetDependency().OrganizationAdmin(data.OrganizationId).Returns(true); sutProvider.GetDependency().GetByIdAsync(default).ReturnsForAnyArgs(data); foreach (var apiKey in resultApiKeys) @@ -140,6 +156,7 @@ public class ServiceAccountsControllerTests public async void GetAccessTokens_User_Success(SutProvider sutProvider, ServiceAccount data, Guid userId, ICollection resultApiKeys) { sutProvider.GetDependency().GetProperUserId(default).ReturnsForAnyArgs(userId); + sutProvider.GetDependency().AccessSecretsManager(data.OrganizationId).Returns(true); sutProvider.GetDependency().OrganizationAdmin(data.OrganizationId).Returns(false); sutProvider.GetDependency().UserHasReadAccessToServiceAccount(default, default).ReturnsForAnyArgs(true); sutProvider.GetDependency().GetByIdAsync(default).ReturnsForAnyArgs(data); diff --git a/test/Common/AutoFixture/SutProviderExtensions.cs b/test/Common/AutoFixture/SutProviderExtensions.cs new file mode 100644 index 0000000000..1fdf226539 --- /dev/null +++ b/test/Common/AutoFixture/SutProviderExtensions.cs @@ -0,0 +1,50 @@ +using AutoFixture; +using Bit.Core.Services; +using Bit.Core.Settings; +using NSubstitute; +using RichardSzalay.MockHttp; + +namespace Bit.Test.Common.AutoFixture; + +public static class SutProviderExtensions +{ + public static SutProvider ConfigureBaseIdentityClientService(this SutProvider sutProvider, + string requestUrlFragment, HttpMethod requestHttpMethod, string identityResponse = null, string apiResponse = null) + where T : BaseIdentityClientService + { + var fixture = new Fixture().WithAutoNSubstitutionsAutoPopulatedProperties(); + fixture.AddMockHttp(); + + var settings = fixture.Create(); + settings.SelfHosted = true; + settings.EnableCloudCommunication = true; + + var apiUri = fixture.Create(); + var identityUri = fixture.Create(); + settings.Installation.ApiUri.Returns(apiUri.ToString()); + settings.Installation.IdentityUri.Returns(identityUri.ToString()); + + var apiHandler = new MockHttpMessageHandler(); + var identityHandler = new MockHttpMessageHandler(); + var syncUri = string.Concat(apiUri, requestUrlFragment); + var tokenUri = string.Concat(identityUri, "connect/token"); + + apiHandler.When(requestHttpMethod, syncUri) + .Respond("application/json", apiResponse); + identityHandler.When(HttpMethod.Post, tokenUri) + .Respond("application/json", identityResponse ?? "{\"access_token\":\"string\",\"expires_in\":3600,\"token_type\":\"Bearer\",\"scope\":\"string\"}"); + + + var apiHttp = apiHandler.ToHttpClient(); + var identityHttp = identityHandler.ToHttpClient(); + + var mockHttpClientFactory = Substitute.For(); + mockHttpClientFactory.CreateClient(Arg.Is("client")).Returns(apiHttp); + mockHttpClientFactory.CreateClient(Arg.Is("identity")).Returns(identityHttp); + + return sutProvider + .SetDependency(settings) + .SetDependency(mockHttpClientFactory) + .Create(); + } +} diff --git a/test/Core.Test/AutoFixture/SubscriptionInfoCustomization.cs b/test/Core.Test/AutoFixture/SubscriptionInfoCustomization.cs new file mode 100644 index 0000000000..d16d13b578 --- /dev/null +++ b/test/Core.Test/AutoFixture/SubscriptionInfoCustomization.cs @@ -0,0 +1,18 @@ +using AutoFixture; +using Bit.Core.Models.Business; +using Bit.Test.Common.AutoFixture.Attributes; + +namespace Bit.Core.Test.AutoFixture; + +public class SubscriptionInfoCustomizeAttribute : BitCustomizeAttribute +{ + public override ICustomization GetCustomization() => new SubscriptionInfoCustomization(); +} +public class SubscriptionInfoCustomization : ICustomization +{ + public void Customize(IFixture fixture) + { + // The Subscription property uses the external Stripe library, which Autofixture doesn't handle + fixture.Customize(c => c.Without(s => s.Subscription)); + } +} diff --git a/test/Core.Test/Entities/OrganizationConnectionTests.cs b/test/Core.Test/Entities/OrganizationConnectionTests.cs new file mode 100644 index 0000000000..32690416c2 --- /dev/null +++ b/test/Core.Test/Entities/OrganizationConnectionTests.cs @@ -0,0 +1,78 @@ +using Bit.Core.Entities; +using Bit.Core.Enums; +using Bit.Core.Models.OrganizationConnectionConfigs; +using Bit.Test.Common.AutoFixture.Attributes; +using Xunit; + +namespace Bit.Core.Test.Entities; + +public class OrganizationConnectionTests +{ + [Theory] + [BitAutoData] + public void OrganizationConnection_CanUse_Success(Guid connectionId, Guid organizationId) + { + var connection = new OrganizationConnection() + { + Id = connectionId, + OrganizationId = organizationId, + Enabled = true, + Type = OrganizationConnectionType.Scim, + Config = new ScimConfig() { Enabled = true } + }; + + Assert.True(connection.Validate(out var exception)); + Assert.True(string.IsNullOrEmpty(exception)); + } + + [Theory] + [BitAutoData] + public void OrganizationConnection_CanUse_WhenDisabled_ReturnsFalse(Guid connectionId, Guid organizationId) + { + + var connection = new OrganizationConnection() + { + Id = connectionId, + OrganizationId = organizationId, + Enabled = false, + Type = OrganizationConnectionType.Scim, + Config = new ScimConfig() { Enabled = true } + }; + + Assert.False(connection.Validate(out var exception)); + Assert.Contains("Connection disabled", exception); + } + + [Theory] + [BitAutoData] + public void OrganizationConnection_CanUse_WhenNoConfig_ReturnsFalse(Guid connectionId, Guid organizationId) + { + var connection = new OrganizationConnection() + { + Id = connectionId, + OrganizationId = organizationId, + Enabled = true, + Type = OrganizationConnectionType.Scim, + }; + + Assert.False(connection.Validate(out var exception)); + Assert.Contains("No saved Connection config", exception); + } + + [Theory] + [BitAutoData] + public void OrganizationConnection_CanUse_WhenConfigInvalid_ReturnsFalse(Guid connectionId, Guid organizationId) + { + var connection = new OrganizationConnection() + { + Id = connectionId, + OrganizationId = organizationId, + Enabled = true, + Type = OrganizationConnectionType.Scim, + Config = new ScimConfig() { Enabled = false } + }; + + Assert.False(connection.Validate(out var exception)); + Assert.Contains("Scim Config is disabled", exception); + } +} diff --git a/test/Core.Test/Models/OrganizationConnectionConfigs/BillingSyncConfigTests.cs b/test/Core.Test/Models/OrganizationConnectionConfigs/BillingSyncConfigTests.cs new file mode 100644 index 0000000000..05e717ebde --- /dev/null +++ b/test/Core.Test/Models/OrganizationConnectionConfigs/BillingSyncConfigTests.cs @@ -0,0 +1,27 @@ +using Bit.Core.Models.OrganizationConnectionConfigs; +using Bit.Test.Common.AutoFixture.Attributes; +using Xunit; + +namespace Bit.Core.Test.Models.OrganizationConnectionConfigs; + +public class BillingSyncConfigTests +{ + [Theory] + [BitAutoData] + public void BillingSyncConfig_CanUse_Success(string billingSyncKey) + { + var config = new BillingSyncConfig() { BillingSyncKey = billingSyncKey }; + + Assert.True(config.Validate(out var exception)); + Assert.True(string.IsNullOrEmpty(exception)); + } + + [Fact] + public void BillingSyncConfig_CanUse_WhenNoKey_ReturnsFalse() + { + var config = new BillingSyncConfig(); + + Assert.False(config.Validate(out var exception)); + Assert.Contains("Failed to get Billing Sync Key", exception); + } +} diff --git a/test/Core.Test/Models/OrganizationConnectionConfigs/ScimConfigTests.cs b/test/Core.Test/Models/OrganizationConnectionConfigs/ScimConfigTests.cs new file mode 100644 index 0000000000..fa476eea26 --- /dev/null +++ b/test/Core.Test/Models/OrganizationConnectionConfigs/ScimConfigTests.cs @@ -0,0 +1,23 @@ +using Bit.Core.Models.OrganizationConnectionConfigs; +using Xunit; + +namespace Bit.Core.Test.Models.OrganizationConnectionConfigs; + +public class ScimConfigTests +{ + [Fact] + public void ScimConfig_CanUse_Success() + { + var config = new ScimConfig() { Enabled = true }; + Assert.True(config.Validate(out var exception)); + Assert.True(string.IsNullOrEmpty(exception)); + } + + [Fact] + public void ScimConfig_CanUse_WhenDisabled_ReturnsFalse() + { + var config = new ScimConfig() { Enabled = false }; + Assert.False(config.Validate(out var exception)); + Assert.Contains("Config is disabled", exception); + } +} diff --git a/test/Core.Test/OrganizationFeatures/OrganizationSponsorships/FamiliesForEnterprise/Cloud/ValidateBillingSyncKeyCommandTests.cs b/test/Core.Test/OrganizationFeatures/OrganizationConnections/ValidateBillingSyncKeyCommandTests.cs similarity index 91% rename from test/Core.Test/OrganizationFeatures/OrganizationSponsorships/FamiliesForEnterprise/Cloud/ValidateBillingSyncKeyCommandTests.cs rename to test/Core.Test/OrganizationFeatures/OrganizationConnections/ValidateBillingSyncKeyCommandTests.cs index 9b01e3035f..349f0316d7 100644 --- a/test/Core.Test/OrganizationFeatures/OrganizationSponsorships/FamiliesForEnterprise/Cloud/ValidateBillingSyncKeyCommandTests.cs +++ b/test/Core.Test/OrganizationFeatures/OrganizationConnections/ValidateBillingSyncKeyCommandTests.cs @@ -1,14 +1,14 @@ using Bit.Core.Entities; using Bit.Core.Enums; using Bit.Core.Exceptions; -using Bit.Core.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterprise.Cloud; +using Bit.Core.OrganizationFeatures.OrganizationConnections; using Bit.Core.Repositories; using Bit.Test.Common.AutoFixture; using Bit.Test.Common.AutoFixture.Attributes; using NSubstitute; using Xunit; -namespace Bit.Core.Test.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterprise.Cloud; +namespace Bit.Core.Test.OrganizationFeatures.OrganizationConnections; [SutProviderCustomize] public class ValidateBillingSyncKeyCommandTests diff --git a/test/Core.Test/OrganizationFeatures/OrganizationLicenses/CloudGetOrganizationLicenseQueryTests.cs b/test/Core.Test/OrganizationFeatures/OrganizationLicenses/CloudGetOrganizationLicenseQueryTests.cs new file mode 100644 index 0000000000..cb896ed717 --- /dev/null +++ b/test/Core.Test/OrganizationFeatures/OrganizationLicenses/CloudGetOrganizationLicenseQueryTests.cs @@ -0,0 +1,64 @@ +using Bit.Core.Entities; +using Bit.Core.Enums; +using Bit.Core.Exceptions; +using Bit.Core.Models.Business; +using Bit.Core.OrganizationFeatures.OrganizationLicenses; +using Bit.Core.Repositories; +using Bit.Core.Services; +using Bit.Core.Test.AutoFixture; +using Bit.Test.Common.AutoFixture; +using Bit.Test.Common.AutoFixture.Attributes; +using NSubstitute; +using NSubstitute.ReturnsExtensions; +using Xunit; + +namespace Bit.Core.Test.OrganizationFeatures.OrganizationLicenses; + +[SubscriptionInfoCustomize] +[OrganizationLicenseCustomize] +[SutProviderCustomize] +public class CloudGetOrganizationLicenseQueryTests +{ + [Theory] + [BitAutoData] + public async Task GetLicenseAsync_InvalidInstallationId_Throws(SutProvider sutProvider, + Organization organization, Guid installationId, int version) + { + sutProvider.GetDependency().GetByIdAsync(installationId).ReturnsNull(); + var exception = await Assert.ThrowsAsync( + async () => await sutProvider.Sut.GetLicenseAsync(organization, installationId, version)); + Assert.Contains("Invalid installation id", exception.Message); + } + + [Theory] + [BitAutoData] + public async Task GetLicenseAsync_DisabledOrganization_Throws(SutProvider sutProvider, + Organization organization, Guid installationId, Installation installation) + { + installation.Enabled = false; + sutProvider.GetDependency().GetByIdAsync(installationId).Returns(installation); + + var exception = await Assert.ThrowsAsync( + async () => await sutProvider.Sut.GetLicenseAsync(organization, installationId)); + Assert.Contains("Invalid installation id", exception.Message); + } + + [Theory] + [BitAutoData] + public async Task GetLicenseAsync_CreatesAndReturns(SutProvider sutProvider, + Organization organization, Guid installationId, Installation installation, SubscriptionInfo subInfo, + byte[] licenseSignature) + { + installation.Enabled = true; + sutProvider.GetDependency().GetByIdAsync(installationId).Returns(installation); + sutProvider.GetDependency().GetSubscriptionAsync(organization).Returns(subInfo); + sutProvider.GetDependency().SignLicense(Arg.Any()).Returns(licenseSignature); + + var result = await sutProvider.Sut.GetLicenseAsync(organization, installationId); + + Assert.Equal(LicenseType.Organization, result.LicenseType); + Assert.Equal(organization.Id, result.Id); + Assert.Equal(installationId, result.InstallationId); + Assert.Equal(licenseSignature, result.SignatureBytes); + } +} diff --git a/test/Core.Test/OrganizationFeatures/OrganizationLicenses/SelfHostedGetOrganizationLicenseQueryTests.cs b/test/Core.Test/OrganizationFeatures/OrganizationLicenses/SelfHostedGetOrganizationLicenseQueryTests.cs new file mode 100644 index 0000000000..df4a93305c --- /dev/null +++ b/test/Core.Test/OrganizationFeatures/OrganizationLicenses/SelfHostedGetOrganizationLicenseQueryTests.cs @@ -0,0 +1,94 @@ +using System.Text.Json; +using Bit.Core.Entities; +using Bit.Core.Exceptions; +using Bit.Core.Models.Business; +using Bit.Core.Models.OrganizationConnectionConfigs; +using Bit.Core.OrganizationFeatures.OrganizationLicenses; +using Bit.Core.Settings; +using Bit.Core.Test.AutoFixture; +using Bit.Test.Common.AutoFixture; +using Bit.Test.Common.AutoFixture.Attributes; +using Bit.Test.Common.Helpers; +using Xunit; + +namespace Bit.Core.Test.OrganizationFeatures.OrganizationLicenses; + +[SutProviderCustomize] +public class SelfHostedGetOrganizationLicenseQueryTests +{ + private static SutProvider GetSutProvider(BillingSyncConfig config, + string apiResponse = null) + { + return new SutProvider() + .ConfigureBaseIdentityClientService($"licenses/organization/{config.CloudOrganizationId}", + HttpMethod.Get, apiResponse: apiResponse); + } + + [Theory] + [BitAutoData] + [OrganizationLicenseCustomize] + public async void GetLicenseAsync_Success(Organization organization, + OrganizationConnection billingSyncConnection, BillingSyncConfig config, OrganizationLicense license) + { + var sutProvider = GetSutProvider(config, JsonSerializer.Serialize(license)); + billingSyncConnection.Enabled = true; + billingSyncConnection.Config = config; + + var result = await sutProvider.Sut.GetLicenseAsync(organization, billingSyncConnection); + AssertHelper.AssertPropertyEqual(result, license); + } + + [Theory] + [BitAutoData] + public async void GetLicenseAsync_WhenNotSelfHosted_Throws(Organization organization, + OrganizationConnection billingSyncConnection, BillingSyncConfig config) + { + var sutProvider = GetSutProvider(config); + sutProvider.GetDependency().SelfHosted = false; + + var exception = await Assert.ThrowsAsync(() => + sutProvider.Sut.GetLicenseAsync(organization, billingSyncConnection)); + Assert.Contains("only available for self-hosted", exception.Message); + } + + [Theory] + [BitAutoData] + public async void GetLicenseAsync_WhenCloudCommunicationDisabled_Throws(Organization organization, + OrganizationConnection billingSyncConnection, BillingSyncConfig config) + { + var sutProvider = GetSutProvider(config); + sutProvider.GetDependency().EnableCloudCommunication = false; + + var exception = await Assert.ThrowsAsync(() => + sutProvider.Sut.GetLicenseAsync(organization, billingSyncConnection)); + Assert.Contains("Cloud communication is disabled", exception.Message); + } + + [Theory] + [BitAutoData] + public async void GetLicenseAsync_WhenCantUseConnection_Throws(Organization organization, + OrganizationConnection billingSyncConnection, BillingSyncConfig config) + { + var sutProvider = GetSutProvider(config); + billingSyncConnection.Enabled = false; + + var exception = await Assert.ThrowsAsync(() => + sutProvider.Sut.GetLicenseAsync(organization, billingSyncConnection)); + Assert.Contains("Connection disabled", exception.Message); + } + + [Theory] + [BitAutoData] + public async void GetLicenseAsync_WhenNullResponse_Throws(Organization organization, + OrganizationConnection billingSyncConnection, BillingSyncConfig config) + { + var sutProvider = GetSutProvider(config); + billingSyncConnection.Enabled = true; + billingSyncConnection.Config = config; + + var exception = await Assert.ThrowsAsync(() => + sutProvider.Sut.GetLicenseAsync(organization, billingSyncConnection)); + Assert.Contains("An error has occurred. Check your internet connection and ensure the billing token is correct.", + exception.Message); + } +} diff --git a/test/Core.Test/OrganizationFeatures/OrganizationSponsorships/FamiliesForEnterprise/SelfHosted/SelfHostedSyncSponsorshipsCommandTests.cs b/test/Core.Test/OrganizationFeatures/OrganizationSponsorships/FamiliesForEnterprise/SelfHosted/SelfHostedSyncSponsorshipsCommandTests.cs index 5ec93a976b..1cfe38bf1d 100644 --- a/test/Core.Test/OrganizationFeatures/OrganizationSponsorships/FamiliesForEnterprise/SelfHosted/SelfHostedSyncSponsorshipsCommandTests.cs +++ b/test/Core.Test/OrganizationFeatures/OrganizationSponsorships/FamiliesForEnterprise/SelfHosted/SelfHostedSyncSponsorshipsCommandTests.cs @@ -1,5 +1,4 @@ using System.Text.Json; -using AutoFixture; using Bit.Core.Entities; using Bit.Core.Exceptions; using Bit.Core.Models.Api.Response.OrganizationSponsorships; @@ -12,55 +11,22 @@ using Bit.Core.Test.AutoFixture.OrganizationSponsorshipFixtures; using Bit.Test.Common.AutoFixture; using Bit.Test.Common.AutoFixture.Attributes; using NSubstitute; -using RichardSzalay.MockHttp; using Xunit; namespace Bit.Core.Test.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterprise.SelfHosted; public class SelfHostedSyncSponsorshipsCommandTests : FamiliesForEnterpriseTestsBase { - - public static SutProvider GetSutProvider(bool enableCloudCommunication = true, string identityResponse = null, string apiResponse = null) + private static SutProvider GetSutProvider(string apiResponse = null) { - var fixture = new Fixture().WithAutoNSubstitutionsAutoPopulatedProperties(); - fixture.AddMockHttp(); - - var settings = fixture.Create(); - settings.SelfHosted = true; - settings.EnableCloudCommunication = enableCloudCommunication; - - var apiUri = fixture.Create(); - var identityUri = fixture.Create(); - settings.Installation.ApiUri.Returns(apiUri.ToString()); - settings.Installation.IdentityUri.Returns(identityUri.ToString()); - - var apiHandler = new MockHttpMessageHandler(); - var identityHandler = new MockHttpMessageHandler(); - var syncUri = string.Concat(apiUri, "organization/sponsorship/sync"); - var tokenUri = string.Concat(identityUri, "connect/token"); - - apiHandler.When(HttpMethod.Post, syncUri) - .Respond("application/json", apiResponse); - identityHandler.When(HttpMethod.Post, tokenUri) - .Respond("application/json", identityResponse ?? "{\"access_token\":\"string\",\"expires_in\":3600,\"token_type\":\"Bearer\",\"scope\":\"string\"}"); - - - var apiHttp = apiHandler.ToHttpClient(); - var identityHttp = identityHandler.ToHttpClient(); - - var mockHttpClientFactory = Substitute.For(); - mockHttpClientFactory.CreateClient(Arg.Is("client")).Returns(apiHttp); - mockHttpClientFactory.CreateClient(Arg.Is("identity")).Returns(identityHttp); - - return new SutProvider(fixture) - .SetDependency(settings) - .SetDependency(mockHttpClientFactory) - .Create(); + return new SutProvider() + .ConfigureBaseIdentityClientService("organization/sponsorship/sync", + HttpMethod.Post, apiResponse: apiResponse); } [Theory] [BitAutoData] - public async Task SyncOrganization_BillingSyncKeyDisabled_ThrowsBadRequest( + public async Task SyncOrganization_BillingSyncConnectionDisabled_ThrowsBadRequest( Guid cloudOrganizationId, OrganizationConnection billingSyncConnection) { var sutProvider = GetSutProvider(); @@ -73,7 +39,7 @@ public class SelfHostedSyncSponsorshipsCommandTests : FamiliesForEnterpriseTests var exception = await Assert.ThrowsAsync(() => sutProvider.Sut.SyncOrganization(billingSyncConnection.OrganizationId, cloudOrganizationId, billingSyncConnection)); - Assert.Contains($"Billing Sync Key disabled", exception.Message); + Assert.Contains($"Connection disabled", exception.Message); await sutProvider.GetDependency() .DidNotReceiveWithAnyArgs() @@ -85,7 +51,7 @@ public class SelfHostedSyncSponsorshipsCommandTests : FamiliesForEnterpriseTests [Theory] [BitAutoData] - public async Task SyncOrganization_BillingSyncKeyEmpty_ThrowsBadRequest( + public async Task SyncOrganization_BillingSyncConfigEmpty_ThrowsBadRequest( Guid cloudOrganizationId, OrganizationConnection billingSyncConnection) { var sutProvider = GetSutProvider(); @@ -94,7 +60,7 @@ public class SelfHostedSyncSponsorshipsCommandTests : FamiliesForEnterpriseTests var exception = await Assert.ThrowsAsync(() => sutProvider.Sut.SyncOrganization(billingSyncConnection.OrganizationId, cloudOrganizationId, billingSyncConnection)); - Assert.Contains($"No Billing Sync Key known", exception.Message); + Assert.Contains($"No saved Connection config", exception.Message); await sutProvider.GetDependency() .DidNotReceiveWithAnyArgs() @@ -109,7 +75,8 @@ public class SelfHostedSyncSponsorshipsCommandTests : FamiliesForEnterpriseTests public async Task SyncOrganization_CloudCommunicationDisabled_EarlyReturn( Guid cloudOrganizationId, OrganizationConnection billingSyncConnection) { - var sutProvider = GetSutProvider(false); + var sutProvider = GetSutProvider(); + sutProvider.GetDependency().EnableCloudCommunication = false; var exception = await Assert.ThrowsAsync(() => sutProvider.Sut.SyncOrganization(billingSyncConnection.OrganizationId, cloudOrganizationId, billingSyncConnection)); @@ -136,7 +103,8 @@ public class SelfHostedSyncSponsorshipsCommandTests : FamiliesForEnterpriseTests SponsorshipsBatch = sponsorships.Select(o => new OrganizationSponsorshipData(o)) })); - var sutProvider = GetSutProvider(apiResponse: syncJsonResponse); + var sutProvider = GetSutProvider(syncJsonResponse); + billingSyncConnection.SetConfig(new BillingSyncConfig { BillingSyncKey = "okslkcslkjf" @@ -166,7 +134,7 @@ public class SelfHostedSyncSponsorshipsCommandTests : FamiliesForEnterpriseTests SponsorshipsBatch = sponsorships.Select(o => new OrganizationSponsorshipData(o) { CloudSponsorshipRemoved = true }) })); - var sutProvider = GetSutProvider(apiResponse: syncJsonResponse); + var sutProvider = GetSutProvider(syncJsonResponse); billingSyncConnection.SetConfig(new BillingSyncConfig { BillingSyncKey = "okslkcslkjf" diff --git a/test/Core.Test/Services/OrganizationServiceTests.cs b/test/Core.Test/Services/OrganizationServiceTests.cs index d112cdf9de..6bc60b85e2 100644 --- a/test/Core.Test/Services/OrganizationServiceTests.cs +++ b/test/Core.Test/Services/OrganizationServiceTests.cs @@ -311,6 +311,7 @@ public class OrganizationServiceTests public async Task InviteUser_WithCustomType_WhenUseCustomPermissionsIsTrue_Passes(Organization organization, OrganizationUserInvite invite, OrganizationUser invitor, SutProvider sutProvider) { + organization.Seats = 10; organization.UseCustomPermissions = true; invite.Permissions = null; @@ -336,6 +337,7 @@ public class OrganizationServiceTests public async Task InviteUser_WithNonCustomType_WhenUseCustomPermissionsIsFalse_Passes(OrganizationUserType inviteUserType, Organization organization, OrganizationUserInvite invite, OrganizationUser invitor, SutProvider sutProvider) { + organization.Seats = 10; organization.UseCustomPermissions = false; invite.Type = inviteUserType; diff --git a/test/Identity.IntegrationTest/openid-configuration.json b/test/Identity.IntegrationTest/openid-configuration.json index 1e95c93db2..9442330da7 100644 --- a/test/Identity.IntegrationTest/openid-configuration.json +++ b/test/Identity.IntegrationTest/openid-configuration.json @@ -28,6 +28,7 @@ "orgcustom", "providerprovideradmin", "providerserviceuser", + "accesssecretsmanager", "sub", "organization" ], diff --git a/test/Infrastructure.EFIntegration.Test/Repositories/CipherRepositoryTests.cs b/test/Infrastructure.EFIntegration.Test/Repositories/CipherRepositoryTests.cs index 7868c7c034..0de2196a88 100644 --- a/test/Infrastructure.EFIntegration.Test/Repositories/CipherRepositoryTests.cs +++ b/test/Infrastructure.EFIntegration.Test/Repositories/CipherRepositoryTests.cs @@ -159,7 +159,7 @@ public class CipherRepositoryTests var postEfCipher = await sut.CreateAsync(cipher); sut.ClearChangeTracking(); - var query = new UserBumpAccountRevisionDateByCipherIdQuery(cipher); + var query = new UserBumpAccountRevisionDateByCipherIdQuery(cipher.Id, cipher.OrganizationId.Value); var modifiedUsers = await sut.Run(query).ToListAsync(); Assert.True(modifiedUsers .All(u => u.AccountRevisionDate.ToShortDateString() == diff --git a/test/IntegrationTestCommon/Factories/WebApplicationFactoryBase.cs b/test/IntegrationTestCommon/Factories/WebApplicationFactoryBase.cs index 18ada0af05..d582d22cb5 100644 --- a/test/IntegrationTestCommon/Factories/WebApplicationFactoryBase.cs +++ b/test/IntegrationTestCommon/Factories/WebApplicationFactoryBase.cs @@ -8,6 +8,8 @@ using Microsoft.AspNetCore.TestHost; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; namespace Bit.IntegrationTestCommon.Factories; @@ -108,6 +110,9 @@ public abstract class WebApplicationFactoryBase : WebApplicationFactory // Fix IP Rate Limiting services.AddSingleton(); + + // Disable logs + services.AddSingleton(); }); } diff --git a/util/Migrator/DbScripts/2023-01-17_00_SecretsManagerOrganizationUser.sql b/util/Migrator/DbScripts/2023-01-17_00_SecretsManagerOrganizationUser.sql new file mode 100644 index 0000000000..f0d36287f8 --- /dev/null +++ b/util/Migrator/DbScripts/2023-01-17_00_SecretsManagerOrganizationUser.sql @@ -0,0 +1,425 @@ +IF COL_LENGTH('[dbo].[OrganizationUser]', 'AccessSecretsManager') IS NULL +BEGIN + ALTER TABLE + [dbo].[OrganizationUser] + ADD + [AccessSecretsManager] BIT NOT NULL CONSTRAINT [DF_OrganizationUser_SecretsManager] DEFAULT (0) +END +GO + +CREATE OR ALTER PROCEDURE [dbo].[OrganizationUser_Update] + @Id UNIQUEIDENTIFIER, + @OrganizationId UNIQUEIDENTIFIER, + @UserId UNIQUEIDENTIFIER, + @Email NVARCHAR(256), + @Key VARCHAR(MAX), + @Status SMALLINT, + @Type TINYINT, + @AccessAll BIT, + @ExternalId NVARCHAR(300), + @CreationDate DATETIME2(7), + @RevisionDate DATETIME2(7), + @Permissions NVARCHAR(MAX), + @ResetPasswordKey VARCHAR(MAX), + @AccessSecretsManager BIT = 0 +AS +BEGIN + SET NOCOUNT ON + + UPDATE + [dbo].[OrganizationUser] + SET + [OrganizationId] = @OrganizationId, + [UserId] = @UserId, + [Email] = @Email, + [Key] = @Key, + [Status] = @Status, + [Type] = @Type, + [AccessAll] = @AccessAll, + [ExternalId] = @ExternalId, + [CreationDate] = @CreationDate, + [RevisionDate] = @RevisionDate, + [Permissions] = @Permissions, + [ResetPasswordKey] = @ResetPasswordKey, + [AccessSecretsManager] = @AccessSecretsManager + WHERE + [Id] = @Id + + EXEC [dbo].[User_BumpAccountRevisionDate] @UserId +END +GO + +CREATE OR ALTER PROCEDURE [dbo].[OrganizationUser_UpdateWithCollections] + @Id UNIQUEIDENTIFIER, + @OrganizationId UNIQUEIDENTIFIER, + @UserId UNIQUEIDENTIFIER, + @Email NVARCHAR(256), + @Key VARCHAR(MAX), + @Status SMALLINT, + @Type TINYINT, + @AccessAll BIT, + @ExternalId NVARCHAR(300), + @CreationDate DATETIME2(7), + @RevisionDate DATETIME2(7), + @Permissions NVARCHAR(MAX), + @ResetPasswordKey VARCHAR(MAX), + @Collections AS [dbo].[SelectionReadOnlyArray] READONLY, + @AccessSecretsManager BIT = 0 +AS +BEGIN + SET NOCOUNT ON + + EXEC [dbo].[OrganizationUser_Update] @Id, @OrganizationId, @UserId, @Email, @Key, @Status, @Type, @AccessAll, @ExternalId, @CreationDate, @RevisionDate, @Permissions, @ResetPasswordKey, @AccessSecretsManager + -- Update + UPDATE + [Target] + SET + [Target].[ReadOnly] = [Source].[ReadOnly], + [Target].[HidePasswords] = [Source].[HidePasswords] + FROM + [dbo].[CollectionUser] AS [Target] + INNER JOIN + @Collections AS [Source] ON [Source].[Id] = [Target].[CollectionId] + WHERE + [Target].[OrganizationUserId] = @Id + AND ( + [Target].[ReadOnly] != [Source].[ReadOnly] + OR [Target].[HidePasswords] != [Source].[HidePasswords] + ) + + -- Insert + INSERT INTO + [dbo].[CollectionUser] + SELECT + [Source].[Id], + @Id, + [Source].[ReadOnly], + [Source].[HidePasswords] + FROM + @Collections AS [Source] + INNER JOIN + [dbo].[Collection] C ON C.[Id] = [Source].[Id] AND C.[OrganizationId] = @OrganizationId + WHERE + NOT EXISTS ( + SELECT + 1 + FROM + [dbo].[CollectionUser] + WHERE + [CollectionId] = [Source].[Id] + AND [OrganizationUserId] = @Id + ) + + -- Delete + DELETE + CU + FROM + [dbo].[CollectionUser] CU + WHERE + CU.[OrganizationUserId] = @Id + AND NOT EXISTS ( + SELECT + 1 + FROM + @Collections + WHERE + [Id] = CU.[CollectionId] + ) +END +GO + +IF OBJECT_ID('[dbo].[OrganizationUserView]') IS NOT NULL +BEGIN + EXECUTE sp_refreshsqlmodule N'[dbo].[OrganizationUserView]'; +END +GO + +CREATE OR ALTER VIEW [dbo].[OrganizationUserUserDetailsView] +AS +SELECT + OU.[Id], + OU.[UserId], + OU.[OrganizationId], + U.[Name], + ISNULL(U.[Email], OU.[Email]) Email, + U.[TwoFactorProviders], + U.[Premium], + OU.[Status], + OU.[Type], + OU.[AccessAll], + OU.[AccessSecretsManager], + OU.[ExternalId], + SU.[ExternalId] SsoExternalId, + OU.[Permissions], + OU.[ResetPasswordKey], + U.[UsesKeyConnector] +FROM + [dbo].[OrganizationUser] OU +LEFT JOIN + [dbo].[User] U ON U.[Id] = OU.[UserId] +LEFT JOIN + [dbo].[SsoUser] SU ON SU.[UserId] = OU.[UserId] AND SU.[OrganizationId] = OU.[OrganizationId] +GO + +CREATE OR ALTER VIEW [dbo].[OrganizationUserOrganizationDetailsView] +AS +SELECT + OU.[UserId], + OU.[OrganizationId], + 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], + O.[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, + SS.[Data] SsoConfig, + OS.[FriendlyName] FamilySponsorshipFriendlyName, + OS.[LastSyncDate] FamilySponsorshipLastSyncDate, + OS.[ToDelete] FamilySponsorshipToDelete, + OS.[ValidUntil] FamilySponsorshipValidUntil, + OU.[AccessSecretsManager] +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 + +CREATE OR ALTER PROCEDURE [dbo].[OrganizationUser_Create] + @Id UNIQUEIDENTIFIER OUTPUT, + @OrganizationId UNIQUEIDENTIFIER, + @UserId UNIQUEIDENTIFIER, + @Email NVARCHAR(256), + @Key VARCHAR(MAX), + @Status SMALLINT, + @Type TINYINT, + @AccessAll BIT, + @ExternalId NVARCHAR(300), + @CreationDate DATETIME2(7), + @RevisionDate DATETIME2(7), + @Permissions NVARCHAR(MAX), + @ResetPasswordKey VARCHAR(MAX), + @AccessSecretsManager BIT = 0 +AS +BEGIN + SET NOCOUNT ON + + INSERT INTO [dbo].[OrganizationUser] + ( + [Id], + [OrganizationId], + [UserId], + [Email], + [Key], + [Status], + [Type], + [AccessAll], + [ExternalId], + [CreationDate], + [RevisionDate], + [Permissions], + [ResetPasswordKey], + [AccessSecretsManager] + ) + VALUES + ( + @Id, + @OrganizationId, + @UserId, + @Email, + @Key, + @Status, + @Type, + @AccessAll, + @ExternalId, + @CreationDate, + @RevisionDate, + @Permissions, + @ResetPasswordKey, + @AccessSecretsManager + ) +END +GO + +CREATE OR ALTER PROCEDURE [dbo].[OrganizationUser_CreateWithCollections] + @Id UNIQUEIDENTIFIER, + @OrganizationId UNIQUEIDENTIFIER, + @UserId UNIQUEIDENTIFIER, + @Email NVARCHAR(256), + @Key VARCHAR(MAX), + @Status SMALLINT, + @Type TINYINT, + @AccessAll BIT, + @ExternalId NVARCHAR(300), + @CreationDate DATETIME2(7), + @RevisionDate DATETIME2(7), + @Permissions NVARCHAR(MAX), + @ResetPasswordKey VARCHAR(MAX), + @Collections AS [dbo].[SelectionReadOnlyArray] READONLY, + @AccessSecretsManager BIT = 0 +AS +BEGIN + SET NOCOUNT ON + + EXEC [dbo].[OrganizationUser_Create] @Id, @OrganizationId, @UserId, @Email, @Key, @Status, @Type, @AccessAll, @ExternalId, @CreationDate, @RevisionDate, @Permissions, @ResetPasswordKey, @AccessSecretsManager + + ;WITH [AvailableCollectionsCTE] AS( + SELECT + [Id] + FROM + [dbo].[Collection] + WHERE + [OrganizationId] = @OrganizationId + ) + INSERT INTO [dbo].[CollectionUser] + ( + [CollectionId], + [OrganizationUserId], + [ReadOnly], + [HidePasswords] + ) + SELECT + [Id], + @Id, + [ReadOnly], + [HidePasswords] + FROM + @Collections + WHERE + [Id] IN (SELECT [Id] FROM [AvailableCollectionsCTE]) +END +GO + +IF TYPE_ID(N'[dbo].[OrganizationUserType2]') IS NULL +BEGIN + CREATE TYPE [dbo].[OrganizationUserType2] AS TABLE( + [Id] UNIQUEIDENTIFIER, + [OrganizationId] UNIQUEIDENTIFIER, + [UserId] UNIQUEIDENTIFIER, + [Email] NVARCHAR(256), + [Key] VARCHAR(MAX), + [Status] SMALLINT, + [Type] TINYINT, + [AccessAll] BIT, + [ExternalId] NVARCHAR(300), + [CreationDate] DATETIME2(7), + [RevisionDate] DATETIME2(7), + [Permissions] NVARCHAR(MAX), + [ResetPasswordKey] VARCHAR(MAX), + [AccessSecretsManager] BIT + ) +END +GO + +CREATE OR ALTER PROCEDURE [dbo].[OrganizationUser_CreateMany2] + @OrganizationUsersInput [dbo].[OrganizationUserType2] READONLY +AS +BEGIN + SET NOCOUNT ON + + INSERT INTO [dbo].[OrganizationUser] + ( + [Id], + [OrganizationId], + [UserId], + [Email], + [Key], + [Status], + [Type], + [AccessAll], + [ExternalId], + [CreationDate], + [RevisionDate], + [Permissions], + [ResetPasswordKey], + [AccessSecretsManager] + ) + SELECT + OU.[Id], + OU.[OrganizationId], + OU.[UserId], + OU.[Email], + OU.[Key], + OU.[Status], + OU.[Type], + OU.[AccessAll], + OU.[ExternalId], + OU.[CreationDate], + OU.[RevisionDate], + OU.[Permissions], + OU.[ResetPasswordKey], + OU.[AccessSecretsManager] + FROM + @OrganizationUsersInput OU +END +GO + +CREATE OR ALTER PROCEDURE [dbo].[OrganizationUser_UpdateMany2] + @OrganizationUsersInput [dbo].[OrganizationUserType2] READONLY +AS +BEGIN + SET NOCOUNT ON + + UPDATE + OU + SET + [OrganizationId] = OUI.[OrganizationId], + [UserId] = OUI.[UserId], + [Email] = OUI.[Email], + [Key] = OUI.[Key], + [Status] = OUI.[Status], + [Type] = OUI.[Type], + [AccessAll] = OUI.[AccessAll], + [ExternalId] = OUI.[ExternalId], + [CreationDate] = OUI.[CreationDate], + [RevisionDate] = OUI.[RevisionDate], + [Permissions] = OUI.[Permissions], + [ResetPasswordKey] = OUI.[ResetPasswordKey], + [AccessSecretsManager] = OUI.[AccessSecretsManager] + FROM + [dbo].[OrganizationUser] OU + INNER JOIN + @OrganizationUsersInput OUI ON OU.Id = OUI.Id + + EXEC [dbo].[User_BumpManyAccountRevisionDates] + ( + SELECT UserId + FROM @OrganizationUsersInput + ) +END +GO diff --git a/util/Migrator/DbScripts/2023-01-24_00_AutoscalingProviderOrgFixes.sql b/util/Migrator/DbScripts/2023-01-24_00_AutoscalingProviderOrgFixes.sql new file mode 100644 index 0000000000..ccea51823a --- /dev/null +++ b/util/Migrator/DbScripts/2023-01-24_00_AutoscalingProviderOrgFixes.sql @@ -0,0 +1,71 @@ +-- SG-992 changes: add planType to provider orgs +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.[SelfHost], + O.[UsersGetPremium], + O.[UseCustomPermissions], + O.[Seats], + O.[MaxCollections], + O.[MaxStorageGb], + O.[Identifier], + PO.[Key], + O.[PublicKey], + O.[PrivateKey], + PU.[Status], + PU.[Type], + PO.[ProviderId], + PU.[Id] ProviderUserId, + P.[Name] ProviderName, + O.[PlanType] -- new prop +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] + GO + + +-- Refresh metadata of stored procs & functions that use the updated view +IF OBJECT_ID('[dbo].[ProviderUserProviderOrganizationDetails_ReadByUserIdStatus]') IS NOT NULL +BEGIN + EXECUTE sp_refreshsqlmodule N'[dbo].[ProviderUserProviderOrganizationDetails_ReadByUserIdStatus]'; +END +GO + + +-- EC-591 / SG-996 changes: add optional status to stored proc +CREATE OR ALTER PROCEDURE [dbo].[ProviderUserUserDetails_ReadByProviderId] +@ProviderId UNIQUEIDENTIFIER, +@Status TINYINT = NULL -- new: this is required to be backwards compatible +AS +BEGIN + SET NOCOUNT ON + +SELECT + * +FROM + [dbo].[ProviderUserUserDetailsView] +WHERE + [ProviderId] = @ProviderId + AND [Status] = COALESCE(@Status, [Status]) -- new +END +GO diff --git a/util/Migrator/DbScripts/2023-02-01_00_LastUserDates.sql b/util/Migrator/DbScripts/2023-02-01_00_LastUserDates.sql new file mode 100644 index 0000000000..53bdc968ca --- /dev/null +++ b/util/Migrator/DbScripts/2023-02-01_00_LastUserDates.sql @@ -0,0 +1,310 @@ +IF COL_LENGTH('dbo.User', 'LastPasswordChangeDate') IS NULL +BEGIN + ALTER TABLE + [dbo].[User] + ADD + [LastPasswordChangeDate] DATETIME2 (7) NULL +END +GO + +IF COL_LENGTH('dbo.User', 'LastKdfChangeDate') IS NULL +BEGIN + ALTER TABLE + [dbo].[User] + ADD + [LastKdfChangeDate] DATETIME2 (7) NULL +END +GO + +IF COL_LENGTH('dbo.User', 'LastKeyRotationDate') IS NULL +BEGIN + ALTER TABLE + [dbo].[User] + ADD + [LastKeyRotationDate] DATETIME2 (7) NULL +END +GO + +IF COL_LENGTH('dbo.User', 'LastEmailChangeDate') IS NULL +BEGIN + ALTER TABLE + [dbo].[User] + ADD + [LastEmailChangeDate] DATETIME2 (7) NULL +END +GO + +CREATE OR ALTER VIEW [dbo].[UserView] +AS +SELECT + * +FROM + [dbo].[User] +GO + +CREATE OR ALTER PROCEDURE [dbo].[User_UpdateKeys] + @Id UNIQUEIDENTIFIER, + @SecurityStamp NVARCHAR(50), + @Key NVARCHAR(MAX), + @PrivateKey VARCHAR(MAX), + @RevisionDate DATETIME2(7), + @AccountRevisionDate DATETIME2(7) = NULL, + @LastKeyRotationDate DATETIME2(7) = NULL +AS +BEGIN + SET NOCOUNT ON + + UPDATE + [dbo].[User] + SET + [SecurityStamp] = @SecurityStamp, + [Key] = @Key, + [PrivateKey] = @PrivateKey, + [RevisionDate] = @RevisionDate, + [AccountRevisionDate] = ISNULL(@AccountRevisionDate, @RevisionDate), + [LastKeyRotationDate] = @LastKeyRotationDate + WHERE + [Id] = @Id +END +GO + +CREATE OR ALTER PROCEDURE [dbo].[User_Create] + @Id UNIQUEIDENTIFIER OUTPUT, + @Name NVARCHAR(50), + @Email NVARCHAR(256), + @EmailVerified BIT, + @MasterPassword NVARCHAR(300), + @MasterPasswordHint NVARCHAR(50), + @Culture NVARCHAR(10), + @SecurityStamp NVARCHAR(50), + @TwoFactorProviders NVARCHAR(MAX), + @TwoFactorRecoveryCode NVARCHAR(32), + @EquivalentDomains NVARCHAR(MAX), + @ExcludedGlobalEquivalentDomains NVARCHAR(MAX), + @AccountRevisionDate DATETIME2(7), + @Key NVARCHAR(MAX), + @PublicKey NVARCHAR(MAX), + @PrivateKey NVARCHAR(MAX), + @Premium BIT, + @PremiumExpirationDate DATETIME2(7), + @RenewalReminderDate DATETIME2(7), + @Storage BIGINT, + @MaxStorageGb SMALLINT, + @Gateway TINYINT, + @GatewayCustomerId VARCHAR(50), + @GatewaySubscriptionId VARCHAR(50), + @ReferenceData VARCHAR(MAX), + @LicenseKey VARCHAR(100), + @Kdf TINYINT, + @KdfIterations INT, + @KdfMemory INT = NULL, + @KdfParallelism INT = NULL, + @CreationDate DATETIME2(7), + @RevisionDate DATETIME2(7), + @ApiKey VARCHAR(30), + @ForcePasswordReset BIT = 0, + @UsesKeyConnector BIT = 0, + @FailedLoginCount INT = 0, + @LastFailedLoginDate DATETIME2(7), + @UnknownDeviceVerificationEnabled BIT = 1, + @AvatarColor VARCHAR(7) = NULL, + @LastPasswordChangeDate DATETIME2(7) = NULL, + @LastKdfChangeDate DATETIME2(7) = NULL, + @LastKeyRotationDate DATETIME2(7) = NULL, + @LastEmailChangeDate DATETIME2(7) = NULL +AS +BEGIN + SET NOCOUNT ON + + INSERT INTO [dbo].[User] + ( + [Id], + [Name], + [Email], + [EmailVerified], + [MasterPassword], + [MasterPasswordHint], + [Culture], + [SecurityStamp], + [TwoFactorProviders], + [TwoFactorRecoveryCode], + [EquivalentDomains], + [ExcludedGlobalEquivalentDomains], + [AccountRevisionDate], + [Key], + [PublicKey], + [PrivateKey], + [Premium], + [PremiumExpirationDate], + [RenewalReminderDate], + [Storage], + [MaxStorageGb], + [Gateway], + [GatewayCustomerId], + [GatewaySubscriptionId], + [ReferenceData], + [LicenseKey], + [Kdf], + [KdfIterations], + [CreationDate], + [RevisionDate], + [ApiKey], + [ForcePasswordReset], + [UsesKeyConnector], + [FailedLoginCount], + [LastFailedLoginDate], + [UnknownDeviceVerificationEnabled], + [AvatarColor], + [KdfMemory], + [KdfParallelism], + [LastPasswordChangeDate], + [LastKdfChangeDate], + [LastKeyRotationDate], + [LastEmailChangeDate] + ) + VALUES + ( + @Id, + @Name, + @Email, + @EmailVerified, + @MasterPassword, + @MasterPasswordHint, + @Culture, + @SecurityStamp, + @TwoFactorProviders, + @TwoFactorRecoveryCode, + @EquivalentDomains, + @ExcludedGlobalEquivalentDomains, + @AccountRevisionDate, + @Key, + @PublicKey, + @PrivateKey, + @Premium, + @PremiumExpirationDate, + @RenewalReminderDate, + @Storage, + @MaxStorageGb, + @Gateway, + @GatewayCustomerId, + @GatewaySubscriptionId, + @ReferenceData, + @LicenseKey, + @Kdf, + @KdfIterations, + @CreationDate, + @RevisionDate, + @ApiKey, + @ForcePasswordReset, + @UsesKeyConnector, + @FailedLoginCount, + @LastFailedLoginDate, + @UnknownDeviceVerificationEnabled, + @AvatarColor, + @KdfMemory, + @KdfParallelism, + @LastPasswordChangeDate, + @LastKdfChangeDate, + @LastKeyRotationDate, + @LastEmailChangeDate + ) +END +GO + +CREATE OR ALTER PROCEDURE [dbo].[User_Update] + @Id UNIQUEIDENTIFIER, + @Name NVARCHAR(50), + @Email NVARCHAR(256), + @EmailVerified BIT, + @MasterPassword NVARCHAR(300), + @MasterPasswordHint NVARCHAR(50), + @Culture NVARCHAR(10), + @SecurityStamp NVARCHAR(50), + @TwoFactorProviders NVARCHAR(MAX), + @TwoFactorRecoveryCode NVARCHAR(32), + @EquivalentDomains NVARCHAR(MAX), + @ExcludedGlobalEquivalentDomains NVARCHAR(MAX), + @AccountRevisionDate DATETIME2(7), + @Key NVARCHAR(MAX), + @PublicKey NVARCHAR(MAX), + @PrivateKey NVARCHAR(MAX), + @Premium BIT, + @PremiumExpirationDate DATETIME2(7), + @RenewalReminderDate DATETIME2(7), + @Storage BIGINT, + @MaxStorageGb SMALLINT, + @Gateway TINYINT, + @GatewayCustomerId VARCHAR(50), + @GatewaySubscriptionId VARCHAR(50), + @ReferenceData VARCHAR(MAX), + @LicenseKey VARCHAR(100), + @Kdf TINYINT, + @KdfIterations INT, + @KdfMemory INT = NULL, + @KdfParallelism INT = NULL, + @CreationDate DATETIME2(7), + @RevisionDate DATETIME2(7), + @ApiKey VARCHAR(30), + @ForcePasswordReset BIT = 0, + @UsesKeyConnector BIT = 0, + @FailedLoginCount INT, + @LastFailedLoginDate DATETIME2(7), + @UnknownDeviceVerificationEnabled BIT = 1, + @AvatarColor VARCHAR(7), + @LastPasswordChangeDate DATETIME2(7) = NULL, + @LastKdfChangeDate DATETIME2(7) = NULL, + @LastKeyRotationDate DATETIME2(7) = NULL, + @LastEmailChangeDate DATETIME2(7) = NULL +AS +BEGIN + SET NOCOUNT ON + + UPDATE + [dbo].[User] + SET + [Name] = @Name, + [Email] = @Email, + [EmailVerified] = @EmailVerified, + [MasterPassword] = @MasterPassword, + [MasterPasswordHint] = @MasterPasswordHint, + [Culture] = @Culture, + [SecurityStamp] = @SecurityStamp, + [TwoFactorProviders] = @TwoFactorProviders, + [TwoFactorRecoveryCode] = @TwoFactorRecoveryCode, + [EquivalentDomains] = @EquivalentDomains, + [ExcludedGlobalEquivalentDomains] = @ExcludedGlobalEquivalentDomains, + [AccountRevisionDate] = @AccountRevisionDate, + [Key] = @Key, + [PublicKey] = @PublicKey, + [PrivateKey] = @PrivateKey, + [Premium] = @Premium, + [PremiumExpirationDate] = @PremiumExpirationDate, + [RenewalReminderDate] = @RenewalReminderDate, + [Storage] = @Storage, + [MaxStorageGb] = @MaxStorageGb, + [Gateway] = @Gateway, + [GatewayCustomerId] = @GatewayCustomerId, + [GatewaySubscriptionId] = @GatewaySubscriptionId, + [ReferenceData] = @ReferenceData, + [LicenseKey] = @LicenseKey, + [Kdf] = @Kdf, + [KdfIterations] = @KdfIterations, + [KdfMemory] = @KdfMemory, + [KdfParallelism] = @KdfParallelism, + [CreationDate] = @CreationDate, + [RevisionDate] = @RevisionDate, + [ApiKey] = @ApiKey, + [ForcePasswordReset] = @ForcePasswordReset, + [UsesKeyConnector] = @UsesKeyConnector, + [FailedLoginCount] = @FailedLoginCount, + [LastFailedLoginDate] = @LastFailedLoginDate, + [UnknownDeviceVerificationEnabled] = @UnknownDeviceVerificationEnabled, + [AvatarColor] = @AvatarColor, + [LastPasswordChangeDate] = @LastPasswordChangeDate, + [LastKdfChangeDate] = @LastKdfChangeDate, + [LastKeyRotationDate] = @LastKeyRotationDate, + [LastEmailChangeDate] = @LastEmailChangeDate + WHERE + [Id] = @Id +END +GO diff --git a/util/Migrator/DbScripts_future/2023-02-FutureMigration.sql b/util/Migrator/DbScripts_future/2023-02-FutureMigration.sql new file mode 100644 index 0000000000..e7336b5553 --- /dev/null +++ b/util/Migrator/DbScripts_future/2023-02-FutureMigration.sql @@ -0,0 +1,17 @@ +IF TYPE_ID(N'[dbo].[OrganizationUserType]') IS NOT NULL +BEGIN + DROP TYPE [dbo].[OrganizationUserType]; +END +GO + +IF OBJECT_ID('[dbo].[OrganizationUser_CreateMany]') IS NOT NULL +BEGIN + DROP PROCEDURE [dbo].[OrganizationUser_CreateMany]; +END +GO + +IF OBJECT_ID('[dbo].[OrganizationUser_UpdateMany]') IS NOT NULL +BEGIN + DROP PROCEDURE [dbo].[OrganizationUser_UpdateMany]; +END +GO diff --git a/util/MySqlMigrations/Migrations/20230201175203_SecretsManagerOrganizationUser.Designer.cs b/util/MySqlMigrations/Migrations/20230201175203_SecretsManagerOrganizationUser.Designer.cs new file mode 100644 index 0000000000..36467a6b2f --- /dev/null +++ b/util/MySqlMigrations/Migrations/20230201175203_SecretsManagerOrganizationUser.Designer.cs @@ -0,0 +1,2120 @@ +// +using System; +using Bit.Infrastructure.EntityFramework.Repositories; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Bit.MySqlMigrations.Migrations +{ + [DbContext(typeof(DatabaseContext))] + [Migration("20230201175203_SecretsManagerOrganizationUser")] + partial class SecretsManagerOrganizationUser + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "6.0.12") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.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("PublicKey") + .HasColumnType("longtext"); + + b.Property("RequestDeviceIdentifier") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("RequestDeviceType") + .HasColumnType("tinyint unsigned"); + + b.Property("RequestFingerprint") + .HasColumnType("longtext"); + + 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("ResponseDeviceId"); + + b.HasIndex("UserId"); + + b.ToTable("AuthRequest", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Cipher", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("Attachments") + .HasColumnType("longtext"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Data") + .HasColumnType("longtext"); + + b.Property("DeletedDate") + .HasColumnType("datetime(6)"); + + b.Property("Favorites") + .HasColumnType("longtext"); + + b.Property("Folders") + .HasColumnType("longtext"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("Reprompt") + .HasColumnType("tinyint unsigned"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("Cipher", (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") + .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("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("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("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Identifier") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("Name") + .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("UserId"); + + b.ToTable("Device", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.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.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("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("ProviderUserId") + .HasColumnType("char(36)"); + + b.Property("SystemUser") + .HasColumnType("tinyint unsigned"); + + b.Property("Type") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("Event", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Folder", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("Folder", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Grant", b => + { + b.Property("Key") + .HasMaxLength(200) + .HasColumnType("varchar(200)"); + + b.Property("ClientId") + .HasMaxLength(200) + .HasColumnType("varchar(200)"); + + b.Property("ConsumedDate") + .HasColumnType("datetime(6)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Data") + .HasColumnType("longtext"); + + b.Property("Description") + .HasMaxLength(200) + .HasColumnType("varchar(200)"); + + b.Property("ExpirationDate") + .HasColumnType("datetime(6)"); + + b.Property("SessionId") + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("SubjectId") + .HasMaxLength(200) + .HasColumnType("varchar(200)"); + + b.Property("Type") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.HasKey("Key"); + + b.ToTable("Grant", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Group", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("AccessAll") + .HasColumnType("tinyint(1)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("ExternalId") + .HasMaxLength(300) + .HasColumnType("varchar(300)"); + + b.Property("Name") + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("Group", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.GroupUser", b => + { + b.Property("GroupId") + .HasColumnType("char(36)"); + + b.Property("OrganizationUserId") + .HasColumnType("char(36)"); + + b.HasKey("GroupId", "OrganizationUserId"); + + b.HasIndex("OrganizationUserId"); + + b.ToTable("GroupUser", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Installation", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("Enabled") + .HasColumnType("tinyint(1)"); + + b.Property("Key") + .HasMaxLength(150) + .HasColumnType("varchar(150)"); + + b.HasKey("Id"); + + b.ToTable("Installation", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Organization", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("BillingEmail") + .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("MaxAutoscaleSeats") + .HasColumnType("int"); + + b.Property("MaxCollections") + .HasColumnType("smallint"); + + b.Property("MaxStorageGb") + .HasColumnType("smallint"); + + b.Property("Name") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("OwnersNotifiedOfAutoscaling") + .HasColumnType("datetime(6)"); + + b.Property("Plan") + .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("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("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.ToTable("Organization", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationApiKey", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("ApiKey") + .HasMaxLength(30) + .HasColumnType("varchar(30)"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("OrganizationApiKey", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationConnection", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("Config") + .HasColumnType("longtext"); + + b.Property("Enabled") + .HasColumnType("tinyint(1)"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("OrganizationConnection", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationSponsorship", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("FriendlyName") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("LastSyncDate") + .HasColumnType("datetime(6)"); + + b.Property("OfferedToEmail") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("PlanSponsorshipType") + .HasColumnType("tinyint unsigned"); + + b.Property("SponsoredOrganizationId") + .HasColumnType("char(36)"); + + b.Property("SponsoringOrganizationId") + .HasColumnType("char(36)"); + + b.Property("SponsoringOrganizationUserId") + .HasColumnType("char(36)"); + + b.Property("ToDelete") + .HasColumnType("tinyint(1)"); + + b.Property("ValidUntil") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.HasIndex("SponsoredOrganizationId"); + + b.HasIndex("SponsoringOrganizationId"); + + b.ToTable("OrganizationSponsorship", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("AccessAll") + .HasColumnType("tinyint(1)"); + + b.Property("AccessSecretsManager") + .HasColumnType("tinyint(1)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("ExternalId") + .HasMaxLength(300) + .HasColumnType("varchar(300)"); + + b.Property("Key") + .HasColumnType("longtext"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("Permissions") + .HasColumnType("longtext"); + + b.Property("ResetPasswordKey") + .HasColumnType("longtext"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Status") + .HasColumnType("smallint"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("OrganizationUser", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.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"); + + b.ToTable("Policy", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.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("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.Models.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.Models.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.Models.Send", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("AccessCount") + .HasColumnType("int"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Data") + .HasColumnType("longtext"); + + b.Property("DeletionDate") + .HasColumnType("datetime(6)"); + + b.Property("Disabled") + .HasColumnType("tinyint(1)"); + + b.Property("ExpirationDate") + .HasColumnType("datetime(6)"); + + b.Property("HideEmail") + .HasColumnType("tinyint(1)"); + + b.Property("Key") + .HasColumnType("longtext"); + + b.Property("MaxAccessCount") + .HasColumnType("int"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("Password") + .HasMaxLength(300) + .HasColumnType("varchar(300)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("Send", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + 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.Models.SsoUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + 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"); + + b.HasIndex("UserId"); + + b.ToTable("SsoUser", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.TaxRate", b => + { + b.Property("Id") + .HasMaxLength(40) + .HasColumnType("varchar(40)"); + + b.Property("Active") + .HasColumnType("tinyint(1)"); + + b.Property("Country") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("PostalCode") + .HasMaxLength(10) + .HasColumnType("varchar(10)"); + + b.Property("Rate") + .HasColumnType("decimal(65,30)"); + + b.Property("State") + .HasMaxLength(2) + .HasColumnType("varchar(2)"); + + b.HasKey("Id"); + + b.ToTable("TaxRate", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Transaction", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("Amount") + .HasColumnType("decimal(65,30)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Details") + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("Gateway") + .HasColumnType("tinyint unsigned"); + + b.Property("GatewayId") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("PaymentMethodType") + .HasColumnType("tinyint unsigned"); + + b.Property("Refunded") + .HasColumnType("tinyint(1)"); + + b.Property("RefundedAmount") + .HasColumnType("decimal(65,30)"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("Transaction", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.User", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("AccountRevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("ApiKey") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("varchar(30)"); + + b.Property("AvatarColor") + .HasMaxLength(7) + .HasColumnType("varchar(7)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Culture") + .HasMaxLength(10) + .HasColumnType("varchar(10)"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("EmailVerified") + .HasColumnType("tinyint(1)"); + + b.Property("EquivalentDomains") + .HasColumnType("longtext"); + + b.Property("ExcludedGlobalEquivalentDomains") + .HasColumnType("longtext"); + + b.Property("FailedLoginCount") + .HasColumnType("int"); + + b.Property("ForcePasswordReset") + .HasColumnType("tinyint(1)"); + + b.Property("Gateway") + .HasColumnType("tinyint unsigned"); + + b.Property("GatewayCustomerId") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("GatewaySubscriptionId") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("Kdf") + .HasColumnType("tinyint unsigned"); + + b.Property("KdfIterations") + .HasColumnType("int"); + + b.Property("KdfMemory") + .HasColumnType("int"); + + b.Property("KdfParallelism") + .HasColumnType("int"); + + b.Property("Key") + .HasColumnType("longtext"); + + b.Property("LastFailedLoginDate") + .HasColumnType("datetime(6)"); + + b.Property("LicenseKey") + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("MasterPassword") + .HasMaxLength(300) + .HasColumnType("varchar(300)"); + + b.Property("MasterPasswordHint") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("MaxStorageGb") + .HasColumnType("smallint"); + + b.Property("Name") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("Premium") + .HasColumnType("tinyint(1)"); + + b.Property("PremiumExpirationDate") + .HasColumnType("datetime(6)"); + + b.Property("PrivateKey") + .HasColumnType("longtext"); + + b.Property("PublicKey") + .HasColumnType("longtext"); + + b.Property("ReferenceData") + .HasColumnType("longtext"); + + b.Property("RenewalReminderDate") + .HasColumnType("datetime(6)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("SecurityStamp") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("Storage") + .HasColumnType("bigint"); + + b.Property("TwoFactorProviders") + .HasColumnType("longtext"); + + b.Property("TwoFactorRecoveryCode") + .HasMaxLength(32) + .HasColumnType("varchar(32)"); + + b.Property("UnknownDeviceVerificationEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("UsesKeyConnector") + .HasColumnType("tinyint(1)"); + + b.HasKey("Id"); + + b.ToTable("User", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.AccessPolicy", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Discriminator") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Read") + .HasColumnType("tinyint(1)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Write") + .HasColumnType("tinyint(1)"); + + b.HasKey("Id") + .HasAnnotation("SqlServer:Clustered", true); + + b.ToTable("AccessPolicy", (string)null); + + b.HasDiscriminator("Discriminator").HasValue("AccessPolicy"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ApiKey", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("ClientSecret") + .HasMaxLength(30) + .HasColumnType("varchar(30)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("EncryptedPayload") + .HasMaxLength(4000) + .HasColumnType("varchar(4000)"); + + b.Property("ExpireAt") + .HasColumnType("datetime(6)"); + + b.Property("Key") + .HasColumnType("longtext"); + + b.Property("Name") + .HasMaxLength(200) + .HasColumnType("varchar(200)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Scope") + .HasMaxLength(4000) + .HasColumnType("varchar(4000)"); + + b.Property("ServiceAccountId") + .HasColumnType("char(36)"); + + b.HasKey("Id") + .HasAnnotation("SqlServer:Clustered", true); + + b.HasIndex("ServiceAccountId") + .HasAnnotation("SqlServer:Clustered", false); + + b.ToTable("ApiKey", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Project", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("DeletedDate") + .HasColumnType("datetime(6)"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.HasKey("Id") + .HasAnnotation("SqlServer:Clustered", true); + + b.HasIndex("DeletedDate") + .HasAnnotation("SqlServer:Clustered", false); + + b.HasIndex("OrganizationId") + .HasAnnotation("SqlServer:Clustered", false); + + b.ToTable("Project", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Secret", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("DeletedDate") + .HasColumnType("datetime(6)"); + + b.Property("Key") + .HasColumnType("longtext"); + + b.Property("Note") + .HasColumnType("longtext"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Value") + .HasColumnType("longtext"); + + b.HasKey("Id") + .HasAnnotation("SqlServer:Clustered", true); + + b.HasIndex("DeletedDate") + .HasAnnotation("SqlServer:Clustered", false); + + b.HasIndex("OrganizationId") + .HasAnnotation("SqlServer:Clustered", false); + + b.ToTable("Secret", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccount", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.HasKey("Id") + .HasAnnotation("SqlServer:Clustered", true); + + b.HasIndex("OrganizationId") + .HasAnnotation("SqlServer:Clustered", false); + + b.ToTable("ServiceAccount", (string)null); + }); + + modelBuilder.Entity("ProjectSecret", b => + { + b.Property("ProjectsId") + .HasColumnType("char(36)"); + + b.Property("SecretsId") + .HasColumnType("char(36)"); + + b.HasKey("ProjectsId", "SecretsId"); + + b.HasIndex("SecretsId"); + + b.ToTable("ProjectSecret"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.GroupProjectAccessPolicy", b => + { + b.HasBaseType("Bit.Infrastructure.EntityFramework.SecretsManager.Models.AccessPolicy"); + + b.Property("GrantedProjectId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("char(36)") + .HasColumnName("GrantedProjectId"); + + b.Property("GroupId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("char(36)") + .HasColumnName("GroupId"); + + b.HasIndex("GrantedProjectId"); + + b.HasIndex("GroupId"); + + b.HasDiscriminator().HasValue("group_project"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.GroupServiceAccountAccessPolicy", b => + { + b.HasBaseType("Bit.Infrastructure.EntityFramework.SecretsManager.Models.AccessPolicy"); + + b.Property("GrantedServiceAccountId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("char(36)") + .HasColumnName("GrantedServiceAccountId"); + + b.Property("GroupId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("char(36)") + .HasColumnName("GroupId"); + + b.HasIndex("GrantedServiceAccountId"); + + b.HasIndex("GroupId"); + + b.HasDiscriminator().HasValue("group_service_account"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccountProjectAccessPolicy", b => + { + b.HasBaseType("Bit.Infrastructure.EntityFramework.SecretsManager.Models.AccessPolicy"); + + b.Property("GrantedProjectId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("char(36)") + .HasColumnName("GrantedProjectId"); + + b.Property("ServiceAccountId") + .HasColumnType("char(36)") + .HasColumnName("ServiceAccountId"); + + b.HasIndex("GrantedProjectId"); + + b.HasIndex("ServiceAccountId"); + + b.HasDiscriminator().HasValue("service_account_project"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.UserProjectAccessPolicy", b => + { + b.HasBaseType("Bit.Infrastructure.EntityFramework.SecretsManager.Models.AccessPolicy"); + + b.Property("GrantedProjectId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("char(36)") + .HasColumnName("GrantedProjectId"); + + b.Property("OrganizationUserId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("char(36)") + .HasColumnName("OrganizationUserId"); + + b.HasIndex("GrantedProjectId"); + + b.HasIndex("OrganizationUserId"); + + b.HasDiscriminator().HasValue("user_project"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.UserServiceAccountAccessPolicy", b => + { + b.HasBaseType("Bit.Infrastructure.EntityFramework.SecretsManager.Models.AccessPolicy"); + + b.Property("GrantedServiceAccountId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("char(36)") + .HasColumnName("GrantedServiceAccountId"); + + b.Property("OrganizationUserId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("char(36)") + .HasColumnName("OrganizationUserId"); + + b.HasIndex("GrantedServiceAccountId"); + + b.HasIndex("OrganizationUserId"); + + b.HasDiscriminator().HasValue("user_service_account"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.AuthRequest", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Device", "ResponseDevice") + .WithMany() + .HasForeignKey("ResponseDeviceId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ResponseDevice"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Cipher", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Ciphers") + .HasForeignKey("OrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("Ciphers") + .HasForeignKey("UserId"); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Collection", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionCipher", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Cipher", "Cipher") + .WithMany("CollectionCiphers") + .HasForeignKey("CipherId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Collection", "Collection") + .WithMany("CollectionCiphers") + .HasForeignKey("CollectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Cipher"); + + b.Navigation("Collection"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionGroup", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Collection", "Collection") + .WithMany("CollectionGroups") + .HasForeignKey("CollectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Group", "Group") + .WithMany() + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Collection"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Collection", "Collection") + .WithMany("CollectionUsers") + .HasForeignKey("CollectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", "OrganizationUser") + .WithMany("CollectionUsers") + .HasForeignKey("OrganizationUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Collection"); + + b.Navigation("OrganizationUser"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Device", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.EmergencyAccess", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "Grantee") + .WithMany() + .HasForeignKey("GranteeId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "Grantor") + .WithMany() + .HasForeignKey("GrantorId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Grantee"); + + b.Navigation("Grantor"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Folder", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("Folders") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Group", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Groups") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.GroupUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Group", "Group") + .WithMany("GroupUsers") + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", "OrganizationUser") + .WithMany("GroupUsers") + .HasForeignKey("OrganizationUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Group"); + + b.Navigation("OrganizationUser"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationApiKey", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("ApiKeys") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationConnection", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Connections") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationSponsorship", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "SponsoredOrganization") + .WithMany() + .HasForeignKey("SponsoredOrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "SponsoringOrganization") + .WithMany() + .HasForeignKey("SponsoringOrganizationId"); + + b.Navigation("SponsoredOrganization"); + + b.Navigation("SponsoringOrganization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("OrganizationUsers") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("OrganizationUsers") + .HasForeignKey("UserId"); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Policy", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Policies") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderOrganization", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Provider", "Provider") + .WithMany() + .HasForeignKey("ProviderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + + b.Navigation("Provider"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Provider", "Provider") + .WithMany() + .HasForeignKey("ProviderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany() + .HasForeignKey("UserId"); + + b.Navigation("Provider"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Send", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany() + .HasForeignKey("UserId"); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoConfig", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("SsoConfigs") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("SsoUsers") + .HasForeignKey("OrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("SsoUsers") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Transaction", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Transactions") + .HasForeignKey("OrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("Transactions") + .HasForeignKey("UserId"); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ApiKey", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccount", "ServiceAccount") + .WithMany() + .HasForeignKey("ServiceAccountId"); + + b.Navigation("ServiceAccount"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Project", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Secret", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccount", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("ProjectSecret", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Project", null) + .WithMany() + .HasForeignKey("ProjectsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Secret", null) + .WithMany() + .HasForeignKey("SecretsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.GroupProjectAccessPolicy", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Project", "GrantedProject") + .WithMany("GroupAccessPolicies") + .HasForeignKey("GrantedProjectId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Group", "Group") + .WithMany() + .HasForeignKey("GroupId"); + + b.Navigation("GrantedProject"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.GroupServiceAccountAccessPolicy", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccount", "GrantedServiceAccount") + .WithMany("GroupAccessPolicies") + .HasForeignKey("GrantedServiceAccountId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Group", "Group") + .WithMany() + .HasForeignKey("GroupId"); + + b.Navigation("GrantedServiceAccount"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccountProjectAccessPolicy", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Project", "GrantedProject") + .WithMany("ServiceAccountAccessPolicies") + .HasForeignKey("GrantedProjectId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccount", "ServiceAccount") + .WithMany() + .HasForeignKey("ServiceAccountId"); + + b.Navigation("GrantedProject"); + + b.Navigation("ServiceAccount"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.UserProjectAccessPolicy", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Project", "GrantedProject") + .WithMany("UserAccessPolicies") + .HasForeignKey("GrantedProjectId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", "OrganizationUser") + .WithMany() + .HasForeignKey("OrganizationUserId"); + + b.Navigation("GrantedProject"); + + b.Navigation("OrganizationUser"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.UserServiceAccountAccessPolicy", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccount", "GrantedServiceAccount") + .WithMany("UserAccessPolicies") + .HasForeignKey("GrantedServiceAccountId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", "OrganizationUser") + .WithMany() + .HasForeignKey("OrganizationUserId"); + + b.Navigation("GrantedServiceAccount"); + + b.Navigation("OrganizationUser"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Cipher", b => + { + b.Navigation("CollectionCiphers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Collection", b => + { + b.Navigation("CollectionCiphers"); + + b.Navigation("CollectionGroups"); + + b.Navigation("CollectionUsers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Group", b => + { + b.Navigation("GroupUsers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Organization", b => + { + b.Navigation("ApiKeys"); + + b.Navigation("Ciphers"); + + b.Navigation("Connections"); + + b.Navigation("Groups"); + + b.Navigation("OrganizationUsers"); + + b.Navigation("Policies"); + + b.Navigation("SsoConfigs"); + + b.Navigation("SsoUsers"); + + b.Navigation("Transactions"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", b => + { + b.Navigation("CollectionUsers"); + + b.Navigation("GroupUsers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.User", b => + { + b.Navigation("Ciphers"); + + b.Navigation("Folders"); + + b.Navigation("OrganizationUsers"); + + b.Navigation("SsoUsers"); + + b.Navigation("Transactions"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Project", b => + { + b.Navigation("GroupAccessPolicies"); + + b.Navigation("ServiceAccountAccessPolicies"); + + b.Navigation("UserAccessPolicies"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccount", b => + { + b.Navigation("GroupAccessPolicies"); + + b.Navigation("UserAccessPolicies"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/util/MySqlMigrations/Migrations/20230201175203_SecretsManagerOrganizationUser.cs b/util/MySqlMigrations/Migrations/20230201175203_SecretsManagerOrganizationUser.cs new file mode 100644 index 0000000000..80f8992139 --- /dev/null +++ b/util/MySqlMigrations/Migrations/20230201175203_SecretsManagerOrganizationUser.cs @@ -0,0 +1,25 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Bit.MySqlMigrations.Migrations; + +public partial class SecretsManagerOrganizationUser : Migration +{ + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "AccessSecretsManager", + table: "OrganizationUser", + type: "tinyint(1)", + nullable: false, + defaultValue: false); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "AccessSecretsManager", + table: "OrganizationUser"); + } +} diff --git a/util/MySqlMigrations/Migrations/20230201192610_LastUserDates.Designer.cs b/util/MySqlMigrations/Migrations/20230201192610_LastUserDates.Designer.cs new file mode 100644 index 0000000000..949d58eb5b --- /dev/null +++ b/util/MySqlMigrations/Migrations/20230201192610_LastUserDates.Designer.cs @@ -0,0 +1,2132 @@ +// +using System; +using Bit.Infrastructure.EntityFramework.Repositories; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Bit.MySqlMigrations.Migrations +{ + [DbContext(typeof(DatabaseContext))] + [Migration("20230201192610_LastUserDates")] + partial class LastUserDates + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "6.0.12") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.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("PublicKey") + .HasColumnType("longtext"); + + b.Property("RequestDeviceIdentifier") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("RequestDeviceType") + .HasColumnType("tinyint unsigned"); + + b.Property("RequestFingerprint") + .HasColumnType("longtext"); + + 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("ResponseDeviceId"); + + b.HasIndex("UserId"); + + b.ToTable("AuthRequest", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Cipher", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("Attachments") + .HasColumnType("longtext"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Data") + .HasColumnType("longtext"); + + b.Property("DeletedDate") + .HasColumnType("datetime(6)"); + + b.Property("Favorites") + .HasColumnType("longtext"); + + b.Property("Folders") + .HasColumnType("longtext"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("Reprompt") + .HasColumnType("tinyint unsigned"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("Cipher", (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") + .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("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("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("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Identifier") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("Name") + .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("UserId"); + + b.ToTable("Device", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.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.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("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("ProviderUserId") + .HasColumnType("char(36)"); + + b.Property("SystemUser") + .HasColumnType("tinyint unsigned"); + + b.Property("Type") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.ToTable("Event", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Folder", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("Folder", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Grant", b => + { + b.Property("Key") + .HasMaxLength(200) + .HasColumnType("varchar(200)"); + + b.Property("ClientId") + .HasMaxLength(200) + .HasColumnType("varchar(200)"); + + b.Property("ConsumedDate") + .HasColumnType("datetime(6)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Data") + .HasColumnType("longtext"); + + b.Property("Description") + .HasMaxLength(200) + .HasColumnType("varchar(200)"); + + b.Property("ExpirationDate") + .HasColumnType("datetime(6)"); + + b.Property("SessionId") + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("SubjectId") + .HasMaxLength(200) + .HasColumnType("varchar(200)"); + + b.Property("Type") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.HasKey("Key"); + + b.ToTable("Grant", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Group", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("AccessAll") + .HasColumnType("tinyint(1)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("ExternalId") + .HasMaxLength(300) + .HasColumnType("varchar(300)"); + + b.Property("Name") + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("Group", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.GroupUser", b => + { + b.Property("GroupId") + .HasColumnType("char(36)"); + + b.Property("OrganizationUserId") + .HasColumnType("char(36)"); + + b.HasKey("GroupId", "OrganizationUserId"); + + b.HasIndex("OrganizationUserId"); + + b.ToTable("GroupUser", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Installation", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("Enabled") + .HasColumnType("tinyint(1)"); + + b.Property("Key") + .HasMaxLength(150) + .HasColumnType("varchar(150)"); + + b.HasKey("Id"); + + b.ToTable("Installation", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Organization", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("BillingEmail") + .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("MaxAutoscaleSeats") + .HasColumnType("int"); + + b.Property("MaxCollections") + .HasColumnType("smallint"); + + b.Property("MaxStorageGb") + .HasColumnType("smallint"); + + b.Property("Name") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("OwnersNotifiedOfAutoscaling") + .HasColumnType("datetime(6)"); + + b.Property("Plan") + .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("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("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.ToTable("Organization", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationApiKey", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("ApiKey") + .HasMaxLength(30) + .HasColumnType("varchar(30)"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("OrganizationApiKey", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationConnection", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("Config") + .HasColumnType("longtext"); + + b.Property("Enabled") + .HasColumnType("tinyint(1)"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("OrganizationConnection", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationSponsorship", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("FriendlyName") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("LastSyncDate") + .HasColumnType("datetime(6)"); + + b.Property("OfferedToEmail") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("PlanSponsorshipType") + .HasColumnType("tinyint unsigned"); + + b.Property("SponsoredOrganizationId") + .HasColumnType("char(36)"); + + b.Property("SponsoringOrganizationId") + .HasColumnType("char(36)"); + + b.Property("SponsoringOrganizationUserId") + .HasColumnType("char(36)"); + + b.Property("ToDelete") + .HasColumnType("tinyint(1)"); + + b.Property("ValidUntil") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.HasIndex("SponsoredOrganizationId"); + + b.HasIndex("SponsoringOrganizationId"); + + b.ToTable("OrganizationSponsorship", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("AccessAll") + .HasColumnType("tinyint(1)"); + + b.Property("AccessSecretsManager") + .HasColumnType("tinyint(1)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("ExternalId") + .HasMaxLength(300) + .HasColumnType("varchar(300)"); + + b.Property("Key") + .HasColumnType("longtext"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("Permissions") + .HasColumnType("longtext"); + + b.Property("ResetPasswordKey") + .HasColumnType("longtext"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Status") + .HasColumnType("smallint"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("OrganizationUser", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.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"); + + b.ToTable("Policy", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.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("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.Models.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.Models.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.Models.Send", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("AccessCount") + .HasColumnType("int"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Data") + .HasColumnType("longtext"); + + b.Property("DeletionDate") + .HasColumnType("datetime(6)"); + + b.Property("Disabled") + .HasColumnType("tinyint(1)"); + + b.Property("ExpirationDate") + .HasColumnType("datetime(6)"); + + b.Property("HideEmail") + .HasColumnType("tinyint(1)"); + + b.Property("Key") + .HasColumnType("longtext"); + + b.Property("MaxAccessCount") + .HasColumnType("int"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("Password") + .HasMaxLength(300) + .HasColumnType("varchar(300)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("Send", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + 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.Models.SsoUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + 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"); + + b.HasIndex("UserId"); + + b.ToTable("SsoUser", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.TaxRate", b => + { + b.Property("Id") + .HasMaxLength(40) + .HasColumnType("varchar(40)"); + + b.Property("Active") + .HasColumnType("tinyint(1)"); + + b.Property("Country") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("PostalCode") + .HasMaxLength(10) + .HasColumnType("varchar(10)"); + + b.Property("Rate") + .HasColumnType("decimal(65,30)"); + + b.Property("State") + .HasMaxLength(2) + .HasColumnType("varchar(2)"); + + b.HasKey("Id"); + + b.ToTable("TaxRate", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Transaction", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("Amount") + .HasColumnType("decimal(65,30)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Details") + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("Gateway") + .HasColumnType("tinyint unsigned"); + + b.Property("GatewayId") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("PaymentMethodType") + .HasColumnType("tinyint unsigned"); + + b.Property("Refunded") + .HasColumnType("tinyint(1)"); + + b.Property("RefundedAmount") + .HasColumnType("decimal(65,30)"); + + b.Property("Type") + .HasColumnType("tinyint unsigned"); + + b.Property("UserId") + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("Transaction", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.User", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("AccountRevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("ApiKey") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("varchar(30)"); + + b.Property("AvatarColor") + .HasMaxLength(7) + .HasColumnType("varchar(7)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Culture") + .HasMaxLength(10) + .HasColumnType("varchar(10)"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("EmailVerified") + .HasColumnType("tinyint(1)"); + + b.Property("EquivalentDomains") + .HasColumnType("longtext"); + + b.Property("ExcludedGlobalEquivalentDomains") + .HasColumnType("longtext"); + + b.Property("FailedLoginCount") + .HasColumnType("int"); + + b.Property("ForcePasswordReset") + .HasColumnType("tinyint(1)"); + + b.Property("Gateway") + .HasColumnType("tinyint unsigned"); + + b.Property("GatewayCustomerId") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("GatewaySubscriptionId") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("Kdf") + .HasColumnType("tinyint unsigned"); + + b.Property("KdfIterations") + .HasColumnType("int"); + + b.Property("KdfMemory") + .HasColumnType("int"); + + b.Property("KdfParallelism") + .HasColumnType("int"); + + b.Property("Key") + .HasColumnType("longtext"); + + b.Property("LastEmailChangeDate") + .HasColumnType("datetime(6)"); + + b.Property("LastFailedLoginDate") + .HasColumnType("datetime(6)"); + + b.Property("LastKdfChangeDate") + .HasColumnType("datetime(6)"); + + b.Property("LastKeyRotationDate") + .HasColumnType("datetime(6)"); + + b.Property("LastPasswordChangeDate") + .HasColumnType("datetime(6)"); + + b.Property("LicenseKey") + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("MasterPassword") + .HasMaxLength(300) + .HasColumnType("varchar(300)"); + + b.Property("MasterPasswordHint") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("MaxStorageGb") + .HasColumnType("smallint"); + + b.Property("Name") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("Premium") + .HasColumnType("tinyint(1)"); + + b.Property("PremiumExpirationDate") + .HasColumnType("datetime(6)"); + + b.Property("PrivateKey") + .HasColumnType("longtext"); + + b.Property("PublicKey") + .HasColumnType("longtext"); + + b.Property("ReferenceData") + .HasColumnType("longtext"); + + b.Property("RenewalReminderDate") + .HasColumnType("datetime(6)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("SecurityStamp") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("Storage") + .HasColumnType("bigint"); + + b.Property("TwoFactorProviders") + .HasColumnType("longtext"); + + b.Property("TwoFactorRecoveryCode") + .HasMaxLength(32) + .HasColumnType("varchar(32)"); + + b.Property("UnknownDeviceVerificationEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("UsesKeyConnector") + .HasColumnType("tinyint(1)"); + + b.HasKey("Id"); + + b.ToTable("User", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.AccessPolicy", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Discriminator") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Read") + .HasColumnType("tinyint(1)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Write") + .HasColumnType("tinyint(1)"); + + b.HasKey("Id") + .HasAnnotation("SqlServer:Clustered", true); + + b.ToTable("AccessPolicy", (string)null); + + b.HasDiscriminator("Discriminator").HasValue("AccessPolicy"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ApiKey", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("ClientSecret") + .HasMaxLength(30) + .HasColumnType("varchar(30)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("EncryptedPayload") + .HasMaxLength(4000) + .HasColumnType("varchar(4000)"); + + b.Property("ExpireAt") + .HasColumnType("datetime(6)"); + + b.Property("Key") + .HasColumnType("longtext"); + + b.Property("Name") + .HasMaxLength(200) + .HasColumnType("varchar(200)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Scope") + .HasMaxLength(4000) + .HasColumnType("varchar(4000)"); + + b.Property("ServiceAccountId") + .HasColumnType("char(36)"); + + b.HasKey("Id") + .HasAnnotation("SqlServer:Clustered", true); + + b.HasIndex("ServiceAccountId") + .HasAnnotation("SqlServer:Clustered", false); + + b.ToTable("ApiKey", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Project", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("DeletedDate") + .HasColumnType("datetime(6)"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.HasKey("Id") + .HasAnnotation("SqlServer:Clustered", true); + + b.HasIndex("DeletedDate") + .HasAnnotation("SqlServer:Clustered", false); + + b.HasIndex("OrganizationId") + .HasAnnotation("SqlServer:Clustered", false); + + b.ToTable("Project", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Secret", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("DeletedDate") + .HasColumnType("datetime(6)"); + + b.Property("Key") + .HasColumnType("longtext"); + + b.Property("Note") + .HasColumnType("longtext"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Value") + .HasColumnType("longtext"); + + b.HasKey("Id") + .HasAnnotation("SqlServer:Clustered", true); + + b.HasIndex("DeletedDate") + .HasAnnotation("SqlServer:Clustered", false); + + b.HasIndex("OrganizationId") + .HasAnnotation("SqlServer:Clustered", false); + + b.ToTable("Secret", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccount", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.HasKey("Id") + .HasAnnotation("SqlServer:Clustered", true); + + b.HasIndex("OrganizationId") + .HasAnnotation("SqlServer:Clustered", false); + + b.ToTable("ServiceAccount", (string)null); + }); + + modelBuilder.Entity("ProjectSecret", b => + { + b.Property("ProjectsId") + .HasColumnType("char(36)"); + + b.Property("SecretsId") + .HasColumnType("char(36)"); + + b.HasKey("ProjectsId", "SecretsId"); + + b.HasIndex("SecretsId"); + + b.ToTable("ProjectSecret"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.GroupProjectAccessPolicy", b => + { + b.HasBaseType("Bit.Infrastructure.EntityFramework.SecretsManager.Models.AccessPolicy"); + + b.Property("GrantedProjectId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("char(36)") + .HasColumnName("GrantedProjectId"); + + b.Property("GroupId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("char(36)") + .HasColumnName("GroupId"); + + b.HasIndex("GrantedProjectId"); + + b.HasIndex("GroupId"); + + b.HasDiscriminator().HasValue("group_project"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.GroupServiceAccountAccessPolicy", b => + { + b.HasBaseType("Bit.Infrastructure.EntityFramework.SecretsManager.Models.AccessPolicy"); + + b.Property("GrantedServiceAccountId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("char(36)") + .HasColumnName("GrantedServiceAccountId"); + + b.Property("GroupId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("char(36)") + .HasColumnName("GroupId"); + + b.HasIndex("GrantedServiceAccountId"); + + b.HasIndex("GroupId"); + + b.HasDiscriminator().HasValue("group_service_account"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccountProjectAccessPolicy", b => + { + b.HasBaseType("Bit.Infrastructure.EntityFramework.SecretsManager.Models.AccessPolicy"); + + b.Property("GrantedProjectId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("char(36)") + .HasColumnName("GrantedProjectId"); + + b.Property("ServiceAccountId") + .HasColumnType("char(36)") + .HasColumnName("ServiceAccountId"); + + b.HasIndex("GrantedProjectId"); + + b.HasIndex("ServiceAccountId"); + + b.HasDiscriminator().HasValue("service_account_project"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.UserProjectAccessPolicy", b => + { + b.HasBaseType("Bit.Infrastructure.EntityFramework.SecretsManager.Models.AccessPolicy"); + + b.Property("GrantedProjectId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("char(36)") + .HasColumnName("GrantedProjectId"); + + b.Property("OrganizationUserId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("char(36)") + .HasColumnName("OrganizationUserId"); + + b.HasIndex("GrantedProjectId"); + + b.HasIndex("OrganizationUserId"); + + b.HasDiscriminator().HasValue("user_project"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.UserServiceAccountAccessPolicy", b => + { + b.HasBaseType("Bit.Infrastructure.EntityFramework.SecretsManager.Models.AccessPolicy"); + + b.Property("GrantedServiceAccountId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("char(36)") + .HasColumnName("GrantedServiceAccountId"); + + b.Property("OrganizationUserId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("char(36)") + .HasColumnName("OrganizationUserId"); + + b.HasIndex("GrantedServiceAccountId"); + + b.HasIndex("OrganizationUserId"); + + b.HasDiscriminator().HasValue("user_service_account"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.AuthRequest", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Device", "ResponseDevice") + .WithMany() + .HasForeignKey("ResponseDeviceId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ResponseDevice"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Cipher", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Ciphers") + .HasForeignKey("OrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("Ciphers") + .HasForeignKey("UserId"); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Collection", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionCipher", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Cipher", "Cipher") + .WithMany("CollectionCiphers") + .HasForeignKey("CipherId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Collection", "Collection") + .WithMany("CollectionCiphers") + .HasForeignKey("CollectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Cipher"); + + b.Navigation("Collection"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionGroup", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Collection", "Collection") + .WithMany("CollectionGroups") + .HasForeignKey("CollectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Group", "Group") + .WithMany() + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Collection"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Collection", "Collection") + .WithMany("CollectionUsers") + .HasForeignKey("CollectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", "OrganizationUser") + .WithMany("CollectionUsers") + .HasForeignKey("OrganizationUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Collection"); + + b.Navigation("OrganizationUser"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Device", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.EmergencyAccess", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "Grantee") + .WithMany() + .HasForeignKey("GranteeId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "Grantor") + .WithMany() + .HasForeignKey("GrantorId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Grantee"); + + b.Navigation("Grantor"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Folder", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("Folders") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Group", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Groups") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.GroupUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Group", "Group") + .WithMany("GroupUsers") + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", "OrganizationUser") + .WithMany("GroupUsers") + .HasForeignKey("OrganizationUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Group"); + + b.Navigation("OrganizationUser"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationApiKey", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("ApiKeys") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationConnection", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Connections") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationSponsorship", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "SponsoredOrganization") + .WithMany() + .HasForeignKey("SponsoredOrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "SponsoringOrganization") + .WithMany() + .HasForeignKey("SponsoringOrganizationId"); + + b.Navigation("SponsoredOrganization"); + + b.Navigation("SponsoringOrganization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("OrganizationUsers") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("OrganizationUsers") + .HasForeignKey("UserId"); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Policy", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Policies") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderOrganization", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Provider", "Provider") + .WithMany() + .HasForeignKey("ProviderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + + b.Navigation("Provider"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Provider", "Provider") + .WithMany() + .HasForeignKey("ProviderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany() + .HasForeignKey("UserId"); + + b.Navigation("Provider"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Send", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany() + .HasForeignKey("UserId"); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoConfig", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("SsoConfigs") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("SsoUsers") + .HasForeignKey("OrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("SsoUsers") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Transaction", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Transactions") + .HasForeignKey("OrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("Transactions") + .HasForeignKey("UserId"); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ApiKey", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccount", "ServiceAccount") + .WithMany() + .HasForeignKey("ServiceAccountId"); + + b.Navigation("ServiceAccount"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Project", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Secret", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccount", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("ProjectSecret", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Project", null) + .WithMany() + .HasForeignKey("ProjectsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Secret", null) + .WithMany() + .HasForeignKey("SecretsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.GroupProjectAccessPolicy", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Project", "GrantedProject") + .WithMany("GroupAccessPolicies") + .HasForeignKey("GrantedProjectId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Group", "Group") + .WithMany() + .HasForeignKey("GroupId"); + + b.Navigation("GrantedProject"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.GroupServiceAccountAccessPolicy", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccount", "GrantedServiceAccount") + .WithMany("GroupAccessPolicies") + .HasForeignKey("GrantedServiceAccountId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Group", "Group") + .WithMany() + .HasForeignKey("GroupId"); + + b.Navigation("GrantedServiceAccount"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccountProjectAccessPolicy", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Project", "GrantedProject") + .WithMany("ServiceAccountAccessPolicies") + .HasForeignKey("GrantedProjectId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccount", "ServiceAccount") + .WithMany() + .HasForeignKey("ServiceAccountId"); + + b.Navigation("GrantedProject"); + + b.Navigation("ServiceAccount"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.UserProjectAccessPolicy", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Project", "GrantedProject") + .WithMany("UserAccessPolicies") + .HasForeignKey("GrantedProjectId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", "OrganizationUser") + .WithMany() + .HasForeignKey("OrganizationUserId"); + + b.Navigation("GrantedProject"); + + b.Navigation("OrganizationUser"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.UserServiceAccountAccessPolicy", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccount", "GrantedServiceAccount") + .WithMany("UserAccessPolicies") + .HasForeignKey("GrantedServiceAccountId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", "OrganizationUser") + .WithMany() + .HasForeignKey("OrganizationUserId"); + + b.Navigation("GrantedServiceAccount"); + + b.Navigation("OrganizationUser"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Cipher", b => + { + b.Navigation("CollectionCiphers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Collection", b => + { + b.Navigation("CollectionCiphers"); + + b.Navigation("CollectionGroups"); + + b.Navigation("CollectionUsers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Group", b => + { + b.Navigation("GroupUsers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Organization", b => + { + b.Navigation("ApiKeys"); + + b.Navigation("Ciphers"); + + b.Navigation("Connections"); + + b.Navigation("Groups"); + + b.Navigation("OrganizationUsers"); + + b.Navigation("Policies"); + + b.Navigation("SsoConfigs"); + + b.Navigation("SsoUsers"); + + b.Navigation("Transactions"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", b => + { + b.Navigation("CollectionUsers"); + + b.Navigation("GroupUsers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.User", b => + { + b.Navigation("Ciphers"); + + b.Navigation("Folders"); + + b.Navigation("OrganizationUsers"); + + b.Navigation("SsoUsers"); + + b.Navigation("Transactions"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Project", b => + { + b.Navigation("GroupAccessPolicies"); + + b.Navigation("ServiceAccountAccessPolicies"); + + b.Navigation("UserAccessPolicies"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccount", b => + { + b.Navigation("GroupAccessPolicies"); + + b.Navigation("UserAccessPolicies"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/util/MySqlMigrations/Migrations/20230201192610_LastUserDates.cs b/util/MySqlMigrations/Migrations/20230201192610_LastUserDates.cs new file mode 100644 index 0000000000..a1e4b8c7a4 --- /dev/null +++ b/util/MySqlMigrations/Migrations/20230201192610_LastUserDates.cs @@ -0,0 +1,54 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Bit.MySqlMigrations.Migrations; + +public partial class LastUserDates : Migration +{ + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "LastEmailChangeDate", + table: "User", + type: "datetime(6)", + nullable: true); + + migrationBuilder.AddColumn( + name: "LastKdfChangeDate", + table: "User", + type: "datetime(6)", + nullable: true); + + migrationBuilder.AddColumn( + name: "LastKeyRotationDate", + table: "User", + type: "datetime(6)", + nullable: true); + + migrationBuilder.AddColumn( + name: "LastPasswordChangeDate", + table: "User", + type: "datetime(6)", + nullable: true); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "LastEmailChangeDate", + table: "User"); + + migrationBuilder.DropColumn( + name: "LastKdfChangeDate", + table: "User"); + + migrationBuilder.DropColumn( + name: "LastKeyRotationDate", + table: "User"); + + migrationBuilder.DropColumn( + name: "LastPasswordChangeDate", + table: "User"); + } +} diff --git a/util/MySqlMigrations/Migrations/DatabaseContextModelSnapshot.cs b/util/MySqlMigrations/Migrations/DatabaseContextModelSnapshot.cs index f36cd0c465..1bbdcd7ccd 100644 --- a/util/MySqlMigrations/Migrations/DatabaseContextModelSnapshot.cs +++ b/util/MySqlMigrations/Migrations/DatabaseContextModelSnapshot.cs @@ -19,80 +19,6 @@ namespace Bit.MySqlMigrations.Migrations .HasAnnotation("ProductVersion", "6.0.12") .HasAnnotation("Relational:MaxIdentifierLength", 64); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.AccessPolicy", b => - { - b.Property("Id") - .HasColumnType("char(36)"); - - b.Property("CreationDate") - .HasColumnType("datetime(6)"); - - b.Property("Discriminator") - .IsRequired() - .HasColumnType("longtext"); - - b.Property("Read") - .HasColumnType("tinyint(1)"); - - b.Property("RevisionDate") - .HasColumnType("datetime(6)"); - - b.Property("Write") - .HasColumnType("tinyint(1)"); - - b.HasKey("Id") - .HasAnnotation("SqlServer:Clustered", true); - - b.ToTable("AccessPolicy", (string)null); - - b.HasDiscriminator("Discriminator").HasValue("AccessPolicy"); - }); - - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ApiKey", b => - { - b.Property("Id") - .HasColumnType("char(36)"); - - b.Property("ClientSecret") - .HasMaxLength(30) - .HasColumnType("varchar(30)"); - - b.Property("CreationDate") - .HasColumnType("datetime(6)"); - - b.Property("EncryptedPayload") - .HasMaxLength(4000) - .HasColumnType("varchar(4000)"); - - b.Property("ExpireAt") - .HasColumnType("datetime(6)"); - - b.Property("Key") - .HasColumnType("longtext"); - - b.Property("Name") - .HasMaxLength(200) - .HasColumnType("varchar(200)"); - - b.Property("RevisionDate") - .HasColumnType("datetime(6)"); - - b.Property("Scope") - .HasMaxLength(4000) - .HasColumnType("varchar(4000)"); - - b.Property("ServiceAccountId") - .HasColumnType("char(36)"); - - b.HasKey("Id") - .HasAnnotation("SqlServer:Clustered", true); - - b.HasIndex("ServiceAccountId") - .HasAnnotation("SqlServer:Clustered", false); - - b.ToTable("ApiKey", (string)null); - }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.AuthRequest", b => { b.Property("Id") @@ -830,6 +756,9 @@ namespace Bit.MySqlMigrations.Migrations b.Property("AccessAll") .HasColumnType("tinyint(1)"); + b.Property("AccessSecretsManager") + .HasColumnType("tinyint(1)"); + b.Property("CreationDate") .HasColumnType("datetime(6)"); @@ -904,38 +833,6 @@ namespace Bit.MySqlMigrations.Migrations b.ToTable("Policy", (string)null); }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Project", b => - { - b.Property("Id") - .HasColumnType("char(36)"); - - b.Property("CreationDate") - .HasColumnType("datetime(6)"); - - b.Property("DeletedDate") - .HasColumnType("datetime(6)"); - - b.Property("Name") - .HasColumnType("longtext"); - - b.Property("OrganizationId") - .HasColumnType("char(36)"); - - b.Property("RevisionDate") - .HasColumnType("datetime(6)"); - - b.HasKey("Id") - .HasAnnotation("SqlServer:Clustered", true); - - b.HasIndex("DeletedDate") - .HasAnnotation("SqlServer:Clustered", false); - - b.HasIndex("OrganizationId") - .HasAnnotation("SqlServer:Clustered", false); - - b.ToTable("Project", (string)null); - }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Provider", b => { b.Property("Id") @@ -1064,44 +961,6 @@ namespace Bit.MySqlMigrations.Migrations b.ToTable("ProviderUser", (string)null); }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Secret", b => - { - b.Property("Id") - .HasColumnType("char(36)"); - - b.Property("CreationDate") - .HasColumnType("datetime(6)"); - - b.Property("DeletedDate") - .HasColumnType("datetime(6)"); - - b.Property("Key") - .HasColumnType("longtext"); - - b.Property("Note") - .HasColumnType("longtext"); - - b.Property("OrganizationId") - .HasColumnType("char(36)"); - - b.Property("RevisionDate") - .HasColumnType("datetime(6)"); - - b.Property("Value") - .HasColumnType("longtext"); - - b.HasKey("Id") - .HasAnnotation("SqlServer:Clustered", true); - - b.HasIndex("DeletedDate") - .HasAnnotation("SqlServer:Clustered", false); - - b.HasIndex("OrganizationId") - .HasAnnotation("SqlServer:Clustered", false); - - b.ToTable("Secret", (string)null); - }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Send", b => { b.Property("Id") @@ -1159,32 +1018,6 @@ namespace Bit.MySqlMigrations.Migrations b.ToTable("Send", (string)null); }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ServiceAccount", b => - { - b.Property("Id") - .HasColumnType("char(36)"); - - b.Property("CreationDate") - .HasColumnType("datetime(6)"); - - b.Property("Name") - .HasColumnType("longtext"); - - b.Property("OrganizationId") - .HasColumnType("char(36)"); - - b.Property("RevisionDate") - .HasColumnType("datetime(6)"); - - b.HasKey("Id") - .HasAnnotation("SqlServer:Clustered", true); - - b.HasIndex("OrganizationId") - .HasAnnotation("SqlServer:Clustered", false); - - b.ToTable("ServiceAccount", (string)null); - }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoConfig", b => { b.Property("Id") @@ -1389,9 +1222,21 @@ namespace Bit.MySqlMigrations.Migrations b.Property("Key") .HasColumnType("longtext"); + b.Property("LastEmailChangeDate") + .HasColumnType("datetime(6)"); + b.Property("LastFailedLoginDate") .HasColumnType("datetime(6)"); + b.Property("LastKdfChangeDate") + .HasColumnType("datetime(6)"); + + b.Property("LastKeyRotationDate") + .HasColumnType("datetime(6)"); + + b.Property("LastPasswordChangeDate") + .HasColumnType("datetime(6)"); + b.Property("LicenseKey") .HasMaxLength(100) .HasColumnType("varchar(100)"); @@ -1458,6 +1303,176 @@ namespace Bit.MySqlMigrations.Migrations b.ToTable("User", (string)null); }); + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.AccessPolicy", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Discriminator") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Read") + .HasColumnType("tinyint(1)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Write") + .HasColumnType("tinyint(1)"); + + b.HasKey("Id") + .HasAnnotation("SqlServer:Clustered", true); + + b.ToTable("AccessPolicy", (string)null); + + b.HasDiscriminator("Discriminator").HasValue("AccessPolicy"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ApiKey", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("ClientSecret") + .HasMaxLength(30) + .HasColumnType("varchar(30)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("EncryptedPayload") + .HasMaxLength(4000) + .HasColumnType("varchar(4000)"); + + b.Property("ExpireAt") + .HasColumnType("datetime(6)"); + + b.Property("Key") + .HasColumnType("longtext"); + + b.Property("Name") + .HasMaxLength(200) + .HasColumnType("varchar(200)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Scope") + .HasMaxLength(4000) + .HasColumnType("varchar(4000)"); + + b.Property("ServiceAccountId") + .HasColumnType("char(36)"); + + b.HasKey("Id") + .HasAnnotation("SqlServer:Clustered", true); + + b.HasIndex("ServiceAccountId") + .HasAnnotation("SqlServer:Clustered", false); + + b.ToTable("ApiKey", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Project", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("DeletedDate") + .HasColumnType("datetime(6)"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.HasKey("Id") + .HasAnnotation("SqlServer:Clustered", true); + + b.HasIndex("DeletedDate") + .HasAnnotation("SqlServer:Clustered", false); + + b.HasIndex("OrganizationId") + .HasAnnotation("SqlServer:Clustered", false); + + b.ToTable("Project", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Secret", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("DeletedDate") + .HasColumnType("datetime(6)"); + + b.Property("Key") + .HasColumnType("longtext"); + + b.Property("Note") + .HasColumnType("longtext"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.Property("Value") + .HasColumnType("longtext"); + + b.HasKey("Id") + .HasAnnotation("SqlServer:Clustered", true); + + b.HasIndex("DeletedDate") + .HasAnnotation("SqlServer:Clustered", false); + + b.HasIndex("OrganizationId") + .HasAnnotation("SqlServer:Clustered", false); + + b.ToTable("Secret", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccount", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Name") + .HasColumnType("longtext"); + + b.Property("OrganizationId") + .HasColumnType("char(36)"); + + b.Property("RevisionDate") + .HasColumnType("datetime(6)"); + + b.HasKey("Id") + .HasAnnotation("SqlServer:Clustered", true); + + b.HasIndex("OrganizationId") + .HasAnnotation("SqlServer:Clustered", false); + + b.ToTable("ServiceAccount", (string)null); + }); + modelBuilder.Entity("ProjectSecret", b => { b.Property("ProjectsId") @@ -1473,9 +1488,9 @@ namespace Bit.MySqlMigrations.Migrations b.ToTable("ProjectSecret"); }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.GroupProjectAccessPolicy", b => + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.GroupProjectAccessPolicy", b => { - b.HasBaseType("Bit.Infrastructure.EntityFramework.Models.AccessPolicy"); + b.HasBaseType("Bit.Infrastructure.EntityFramework.SecretsManager.Models.AccessPolicy"); b.Property("GrantedProjectId") .ValueGeneratedOnUpdateSometimes() @@ -1494,9 +1509,9 @@ namespace Bit.MySqlMigrations.Migrations b.HasDiscriminator().HasValue("group_project"); }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.GroupServiceAccountAccessPolicy", b => + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.GroupServiceAccountAccessPolicy", b => { - b.HasBaseType("Bit.Infrastructure.EntityFramework.Models.AccessPolicy"); + b.HasBaseType("Bit.Infrastructure.EntityFramework.SecretsManager.Models.AccessPolicy"); b.Property("GrantedServiceAccountId") .ValueGeneratedOnUpdateSometimes() @@ -1515,9 +1530,9 @@ namespace Bit.MySqlMigrations.Migrations b.HasDiscriminator().HasValue("group_service_account"); }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ServiceAccountProjectAccessPolicy", b => + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccountProjectAccessPolicy", b => { - b.HasBaseType("Bit.Infrastructure.EntityFramework.Models.AccessPolicy"); + b.HasBaseType("Bit.Infrastructure.EntityFramework.SecretsManager.Models.AccessPolicy"); b.Property("GrantedProjectId") .ValueGeneratedOnUpdateSometimes() @@ -1535,9 +1550,9 @@ namespace Bit.MySqlMigrations.Migrations b.HasDiscriminator().HasValue("service_account_project"); }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.UserProjectAccessPolicy", b => + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.UserProjectAccessPolicy", b => { - b.HasBaseType("Bit.Infrastructure.EntityFramework.Models.AccessPolicy"); + b.HasBaseType("Bit.Infrastructure.EntityFramework.SecretsManager.Models.AccessPolicy"); b.Property("GrantedProjectId") .ValueGeneratedOnUpdateSometimes() @@ -1556,9 +1571,9 @@ namespace Bit.MySqlMigrations.Migrations b.HasDiscriminator().HasValue("user_project"); }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.UserServiceAccountAccessPolicy", b => + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.UserServiceAccountAccessPolicy", b => { - b.HasBaseType("Bit.Infrastructure.EntityFramework.Models.AccessPolicy"); + b.HasBaseType("Bit.Infrastructure.EntityFramework.SecretsManager.Models.AccessPolicy"); b.Property("GrantedServiceAccountId") .ValueGeneratedOnUpdateSometimes() @@ -1577,15 +1592,6 @@ namespace Bit.MySqlMigrations.Migrations b.HasDiscriminator().HasValue("user_service_account"); }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ApiKey", b => - { - b.HasOne("Bit.Infrastructure.EntityFramework.Models.ServiceAccount", "ServiceAccount") - .WithMany() - .HasForeignKey("ServiceAccountId"); - - b.Navigation("ServiceAccount"); - }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.AuthRequest", b => { b.HasOne("Bit.Infrastructure.EntityFramework.Models.Device", "ResponseDevice") @@ -1820,17 +1826,6 @@ namespace Bit.MySqlMigrations.Migrations b.Navigation("Organization"); }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Project", b => - { - b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") - .WithMany() - .HasForeignKey("OrganizationId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Organization"); - }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderOrganization", b => { b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") @@ -1867,17 +1862,6 @@ namespace Bit.MySqlMigrations.Migrations b.Navigation("User"); }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Secret", b => - { - b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") - .WithMany() - .HasForeignKey("OrganizationId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Organization"); - }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Send", b => { b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") @@ -1893,17 +1877,6 @@ namespace Bit.MySqlMigrations.Migrations b.Navigation("User"); }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ServiceAccount", b => - { - b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") - .WithMany() - .HasForeignKey("OrganizationId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Organization"); - }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoConfig", b => { b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") @@ -1947,24 +1920,66 @@ namespace Bit.MySqlMigrations.Migrations b.Navigation("User"); }); + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ApiKey", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccount", "ServiceAccount") + .WithMany() + .HasForeignKey("ServiceAccountId"); + + b.Navigation("ServiceAccount"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Project", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Secret", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccount", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + modelBuilder.Entity("ProjectSecret", b => { - b.HasOne("Bit.Infrastructure.EntityFramework.Models.Project", null) + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Project", null) .WithMany() .HasForeignKey("ProjectsId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("Bit.Infrastructure.EntityFramework.Models.Secret", null) + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Secret", null) .WithMany() .HasForeignKey("SecretsId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.GroupProjectAccessPolicy", b => + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.GroupProjectAccessPolicy", b => { - b.HasOne("Bit.Infrastructure.EntityFramework.Models.Project", "GrantedProject") + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Project", "GrantedProject") .WithMany("GroupAccessPolicies") .HasForeignKey("GrantedProjectId"); @@ -1977,10 +1992,10 @@ namespace Bit.MySqlMigrations.Migrations b.Navigation("Group"); }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.GroupServiceAccountAccessPolicy", b => + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.GroupServiceAccountAccessPolicy", b => { - b.HasOne("Bit.Infrastructure.EntityFramework.Models.ServiceAccount", "GrantedServiceAccount") - .WithMany() + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccount", "GrantedServiceAccount") + .WithMany("GroupAccessPolicies") .HasForeignKey("GrantedServiceAccountId"); b.HasOne("Bit.Infrastructure.EntityFramework.Models.Group", "Group") @@ -1992,13 +2007,13 @@ namespace Bit.MySqlMigrations.Migrations b.Navigation("Group"); }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ServiceAccountProjectAccessPolicy", b => + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccountProjectAccessPolicy", b => { - b.HasOne("Bit.Infrastructure.EntityFramework.Models.Project", "GrantedProject") + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Project", "GrantedProject") .WithMany("ServiceAccountAccessPolicies") .HasForeignKey("GrantedProjectId"); - b.HasOne("Bit.Infrastructure.EntityFramework.Models.ServiceAccount", "ServiceAccount") + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccount", "ServiceAccount") .WithMany() .HasForeignKey("ServiceAccountId"); @@ -2007,9 +2022,9 @@ namespace Bit.MySqlMigrations.Migrations b.Navigation("ServiceAccount"); }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.UserProjectAccessPolicy", b => + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.UserProjectAccessPolicy", b => { - b.HasOne("Bit.Infrastructure.EntityFramework.Models.Project", "GrantedProject") + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Project", "GrantedProject") .WithMany("UserAccessPolicies") .HasForeignKey("GrantedProjectId"); @@ -2022,10 +2037,10 @@ namespace Bit.MySqlMigrations.Migrations b.Navigation("OrganizationUser"); }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.UserServiceAccountAccessPolicy", b => + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.UserServiceAccountAccessPolicy", b => { - b.HasOne("Bit.Infrastructure.EntityFramework.Models.ServiceAccount", "GrantedServiceAccount") - .WithMany() + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccount", "GrantedServiceAccount") + .WithMany("UserAccessPolicies") .HasForeignKey("GrantedServiceAccountId"); b.HasOne("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", "OrganizationUser") @@ -2084,15 +2099,6 @@ namespace Bit.MySqlMigrations.Migrations b.Navigation("GroupUsers"); }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Project", b => - { - b.Navigation("GroupAccessPolicies"); - - b.Navigation("ServiceAccountAccessPolicies"); - - b.Navigation("UserAccessPolicies"); - }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.User", b => { b.Navigation("Ciphers"); @@ -2105,6 +2111,22 @@ namespace Bit.MySqlMigrations.Migrations b.Navigation("Transactions"); }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Project", b => + { + b.Navigation("GroupAccessPolicies"); + + b.Navigation("ServiceAccountAccessPolicies"); + + b.Navigation("UserAccessPolicies"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccount", b => + { + b.Navigation("GroupAccessPolicies"); + + b.Navigation("UserAccessPolicies"); + }); #pragma warning restore 612, 618 } } diff --git a/util/PostgresMigrations/Migrations/20230201175207_SecretsManagerOrganizationUser.Designer.cs b/util/PostgresMigrations/Migrations/20230201175207_SecretsManagerOrganizationUser.Designer.cs new file mode 100644 index 0000000000..53d447242e --- /dev/null +++ b/util/PostgresMigrations/Migrations/20230201175207_SecretsManagerOrganizationUser.Designer.cs @@ -0,0 +1,2131 @@ +// +using System; +using Bit.Infrastructure.EntityFramework.Repositories; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace Bit.PostgresMigrations.Migrations +{ + [DbContext(typeof(DatabaseContext))] + [Migration("20230201175207_SecretsManagerOrganizationUser")] + partial class SecretsManagerOrganizationUser + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("Npgsql:CollationDefinition:postgresIndetermanisticCollation", "en-u-ks-primary,en-u-ks-primary,icu,False") + .HasAnnotation("ProductVersion", "6.0.12") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.AuthRequest", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AccessCode") + .HasMaxLength(25) + .HasColumnType("character varying(25)"); + + b.Property("Approved") + .HasColumnType("boolean"); + + b.Property("AuthenticationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Key") + .HasColumnType("text"); + + b.Property("MasterPasswordHash") + .HasColumnType("text"); + + b.Property("PublicKey") + .HasColumnType("text"); + + b.Property("RequestDeviceIdentifier") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("RequestDeviceType") + .HasColumnType("smallint"); + + b.Property("RequestFingerprint") + .HasColumnType("text"); + + b.Property("RequestIpAddress") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("ResponseDate") + .HasColumnType("timestamp with time zone"); + + b.Property("ResponseDeviceId") + .HasColumnType("uuid"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("ResponseDeviceId"); + + b.HasIndex("UserId"); + + b.ToTable("AuthRequest", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Cipher", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Attachments") + .HasColumnType("text"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Data") + .HasColumnType("text"); + + b.Property("DeletedDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Favorites") + .HasColumnType("text"); + + b.Property("Folders") + .HasColumnType("text"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("Reprompt") + .HasColumnType("smallint"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("Cipher", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Collection", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("ExternalId") + .HasMaxLength(300) + .HasColumnType("character varying(300)"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("Collection", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionCipher", b => + { + b.Property("CollectionId") + .HasColumnType("uuid"); + + b.Property("CipherId") + .HasColumnType("uuid"); + + b.HasKey("CollectionId", "CipherId"); + + b.HasIndex("CipherId"); + + b.ToTable("CollectionCipher", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionGroup", b => + { + b.Property("CollectionId") + .HasColumnType("uuid"); + + b.Property("GroupId") + .HasColumnType("uuid"); + + b.Property("HidePasswords") + .HasColumnType("boolean"); + + b.Property("ReadOnly") + .HasColumnType("boolean"); + + b.HasKey("CollectionId", "GroupId"); + + b.HasIndex("GroupId"); + + b.ToTable("CollectionGroups"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionUser", b => + { + b.Property("CollectionId") + .HasColumnType("uuid"); + + b.Property("OrganizationUserId") + .HasColumnType("uuid"); + + b.Property("HidePasswords") + .HasColumnType("boolean"); + + b.Property("ReadOnly") + .HasColumnType("boolean"); + + b.HasKey("CollectionId", "OrganizationUserId"); + + b.HasIndex("OrganizationUserId"); + + b.ToTable("CollectionUsers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Device", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Identifier") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Name") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("PushToken") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("Device", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.EmergencyAccess", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("GranteeId") + .HasColumnType("uuid"); + + b.Property("GrantorId") + .HasColumnType("uuid"); + + b.Property("KeyEncrypted") + .HasColumnType("text"); + + b.Property("LastNotificationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("RecoveryInitiatedDate") + .HasColumnType("timestamp with time zone"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Status") + .HasColumnType("smallint"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.Property("WaitTimeDays") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("GranteeId"); + + b.HasIndex("GrantorId"); + + b.ToTable("EmergencyAccess", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Event", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ActingUserId") + .HasColumnType("uuid"); + + b.Property("CipherId") + .HasColumnType("uuid"); + + b.Property("CollectionId") + .HasColumnType("uuid"); + + b.Property("Date") + .HasColumnType("timestamp with time zone"); + + b.Property("DeviceType") + .HasColumnType("smallint"); + + b.Property("GroupId") + .HasColumnType("uuid"); + + b.Property("InstallationId") + .HasColumnType("uuid"); + + b.Property("IpAddress") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("OrganizationUserId") + .HasColumnType("uuid"); + + b.Property("PolicyId") + .HasColumnType("uuid"); + + b.Property("ProviderId") + .HasColumnType("uuid"); + + b.Property("ProviderOrganizationId") + .HasColumnType("uuid"); + + b.Property("ProviderUserId") + .HasColumnType("uuid"); + + b.Property("SystemUser") + .HasColumnType("smallint"); + + b.Property("Type") + .HasColumnType("integer"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.ToTable("Event", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Folder", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("Folder", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Grant", b => + { + b.Property("Key") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ClientId") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ConsumedDate") + .HasColumnType("timestamp with time zone"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Data") + .HasColumnType("text"); + + b.Property("Description") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ExpirationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("SessionId") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("SubjectId") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Type") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.HasKey("Key"); + + b.ToTable("Grant", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Group", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AccessAll") + .HasColumnType("boolean"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("ExternalId") + .HasMaxLength(300) + .HasColumnType("character varying(300)"); + + b.Property("Name") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("Group", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.GroupUser", b => + { + b.Property("GroupId") + .HasColumnType("uuid"); + + b.Property("OrganizationUserId") + .HasColumnType("uuid"); + + b.HasKey("GroupId", "OrganizationUserId"); + + b.HasIndex("OrganizationUserId"); + + b.ToTable("GroupUser", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Installation", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("Key") + .HasMaxLength(150) + .HasColumnType("character varying(150)"); + + b.HasKey("Id"); + + b.ToTable("Installation", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Organization", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("BillingEmail") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("BusinessAddress1") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("BusinessAddress2") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("BusinessAddress3") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("BusinessCountry") + .HasMaxLength(2) + .HasColumnType("character varying(2)"); + + b.Property("BusinessName") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("BusinessTaxNumber") + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("ExpirationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Gateway") + .HasColumnType("smallint"); + + b.Property("GatewayCustomerId") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("GatewaySubscriptionId") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Identifier") + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .UseCollation("postgresIndetermanisticCollation"); + + b.Property("LicenseKey") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("MaxAutoscaleSeats") + .HasColumnType("integer"); + + b.Property("MaxCollections") + .HasColumnType("smallint"); + + b.Property("MaxStorageGb") + .HasColumnType("smallint"); + + b.Property("Name") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("OwnersNotifiedOfAutoscaling") + .HasColumnType("timestamp with time zone"); + + b.Property("Plan") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("PlanType") + .HasColumnType("smallint"); + + b.Property("PrivateKey") + .HasColumnType("text"); + + b.Property("PublicKey") + .HasColumnType("text"); + + b.Property("ReferenceData") + .HasColumnType("text"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Seats") + .HasColumnType("integer"); + + b.Property("SelfHost") + .HasColumnType("boolean"); + + b.Property("Storage") + .HasColumnType("bigint"); + + b.Property("TwoFactorProviders") + .HasColumnType("text"); + + b.Property("Use2fa") + .HasColumnType("boolean"); + + b.Property("UseApi") + .HasColumnType("boolean"); + + b.Property("UseCustomPermissions") + .HasColumnType("boolean"); + + b.Property("UseDirectory") + .HasColumnType("boolean"); + + b.Property("UseEvents") + .HasColumnType("boolean"); + + b.Property("UseGroups") + .HasColumnType("boolean"); + + b.Property("UseKeyConnector") + .HasColumnType("boolean"); + + b.Property("UsePolicies") + .HasColumnType("boolean"); + + b.Property("UseResetPassword") + .HasColumnType("boolean"); + + b.Property("UseScim") + .HasColumnType("boolean"); + + b.Property("UseSecretsManager") + .HasColumnType("boolean"); + + b.Property("UseSso") + .HasColumnType("boolean"); + + b.Property("UseTotp") + .HasColumnType("boolean"); + + b.Property("UsersGetPremium") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.ToTable("Organization", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationApiKey", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApiKey") + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("OrganizationApiKey", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationConnection", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Config") + .HasColumnType("text"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("OrganizationConnection", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationSponsorship", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("FriendlyName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("LastSyncDate") + .HasColumnType("timestamp with time zone"); + + b.Property("OfferedToEmail") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("PlanSponsorshipType") + .HasColumnType("smallint"); + + b.Property("SponsoredOrganizationId") + .HasColumnType("uuid"); + + b.Property("SponsoringOrganizationId") + .HasColumnType("uuid"); + + b.Property("SponsoringOrganizationUserId") + .HasColumnType("uuid"); + + b.Property("ToDelete") + .HasColumnType("boolean"); + + b.Property("ValidUntil") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("SponsoredOrganizationId"); + + b.HasIndex("SponsoringOrganizationId"); + + b.ToTable("OrganizationSponsorship", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AccessAll") + .HasColumnType("boolean"); + + b.Property("AccessSecretsManager") + .HasColumnType("boolean"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("ExternalId") + .HasMaxLength(300) + .HasColumnType("character varying(300)"); + + b.Property("Key") + .HasColumnType("text"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("Permissions") + .HasColumnType("text"); + + b.Property("ResetPasswordKey") + .HasColumnType("text"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Status") + .HasColumnType("smallint"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("OrganizationUser", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Policy", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Data") + .HasColumnType("text"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("Policy", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Provider", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("BillingEmail") + .HasColumnType("text"); + + b.Property("BillingPhone") + .HasColumnType("text"); + + b.Property("BusinessAddress1") + .HasColumnType("text"); + + b.Property("BusinessAddress2") + .HasColumnType("text"); + + b.Property("BusinessAddress3") + .HasColumnType("text"); + + b.Property("BusinessCountry") + .HasColumnType("text"); + + b.Property("BusinessName") + .HasColumnType("text"); + + b.Property("BusinessTaxNumber") + .HasColumnType("text"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Status") + .HasColumnType("smallint"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.Property("UseEvents") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.ToTable("Provider", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderOrganization", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Key") + .HasColumnType("text"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("ProviderId") + .HasColumnType("uuid"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Settings") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("ProviderId"); + + b.ToTable("ProviderOrganization", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderUser", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Email") + .HasColumnType("text"); + + b.Property("Key") + .HasColumnType("text"); + + b.Property("Permissions") + .HasColumnType("text"); + + b.Property("ProviderId") + .HasColumnType("uuid"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Status") + .HasColumnType("smallint"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("ProviderId"); + + b.HasIndex("UserId"); + + b.ToTable("ProviderUser", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Send", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AccessCount") + .HasColumnType("integer"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Data") + .HasColumnType("text"); + + b.Property("DeletionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Disabled") + .HasColumnType("boolean"); + + b.Property("ExpirationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("HideEmail") + .HasColumnType("boolean"); + + b.Property("Key") + .HasColumnType("text"); + + b.Property("MaxAccessCount") + .HasColumnType("integer"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("Password") + .HasMaxLength(300) + .HasColumnType("character varying(300)"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("Send", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Data") + .HasColumnType("text"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("SsoConfig", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("ExternalId") + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .UseCollation("postgresIndetermanisticCollation"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("SsoUser", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.TaxRate", b => + { + b.Property("Id") + .HasMaxLength(40) + .HasColumnType("character varying(40)"); + + b.Property("Active") + .HasColumnType("boolean"); + + b.Property("Country") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("PostalCode") + .HasMaxLength(10) + .HasColumnType("character varying(10)"); + + b.Property("Rate") + .HasColumnType("numeric"); + + b.Property("State") + .HasMaxLength(2) + .HasColumnType("character varying(2)"); + + b.HasKey("Id"); + + b.ToTable("TaxRate", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Transaction", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Amount") + .HasColumnType("numeric"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Details") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("Gateway") + .HasColumnType("smallint"); + + b.Property("GatewayId") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("PaymentMethodType") + .HasColumnType("smallint"); + + b.Property("Refunded") + .HasColumnType("boolean"); + + b.Property("RefundedAmount") + .HasColumnType("numeric"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("Transaction", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.User", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AccountRevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("ApiKey") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("AvatarColor") + .HasMaxLength(7) + .HasColumnType("character varying(7)"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Culture") + .HasMaxLength(10) + .HasColumnType("character varying(10)"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .UseCollation("postgresIndetermanisticCollation"); + + b.Property("EmailVerified") + .HasColumnType("boolean"); + + b.Property("EquivalentDomains") + .HasColumnType("text"); + + b.Property("ExcludedGlobalEquivalentDomains") + .HasColumnType("text"); + + b.Property("FailedLoginCount") + .HasColumnType("integer"); + + b.Property("ForcePasswordReset") + .HasColumnType("boolean"); + + b.Property("Gateway") + .HasColumnType("smallint"); + + b.Property("GatewayCustomerId") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("GatewaySubscriptionId") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Kdf") + .HasColumnType("smallint"); + + b.Property("KdfIterations") + .HasColumnType("integer"); + + b.Property("KdfMemory") + .HasColumnType("integer"); + + b.Property("KdfParallelism") + .HasColumnType("integer"); + + b.Property("Key") + .HasColumnType("text"); + + b.Property("LastFailedLoginDate") + .HasColumnType("timestamp with time zone"); + + b.Property("LicenseKey") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("MasterPassword") + .HasMaxLength(300) + .HasColumnType("character varying(300)"); + + b.Property("MasterPasswordHint") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("MaxStorageGb") + .HasColumnType("smallint"); + + b.Property("Name") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Premium") + .HasColumnType("boolean"); + + b.Property("PremiumExpirationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("PrivateKey") + .HasColumnType("text"); + + b.Property("PublicKey") + .HasColumnType("text"); + + b.Property("ReferenceData") + .HasColumnType("text"); + + b.Property("RenewalReminderDate") + .HasColumnType("timestamp with time zone"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("SecurityStamp") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Storage") + .HasColumnType("bigint"); + + b.Property("TwoFactorProviders") + .HasColumnType("text"); + + b.Property("TwoFactorRecoveryCode") + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.Property("UnknownDeviceVerificationEnabled") + .HasColumnType("boolean"); + + b.Property("UsesKeyConnector") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.ToTable("User", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.AccessPolicy", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Discriminator") + .IsRequired() + .HasColumnType("text"); + + b.Property("Read") + .HasColumnType("boolean"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Write") + .HasColumnType("boolean"); + + b.HasKey("Id") + .HasAnnotation("SqlServer:Clustered", true); + + b.ToTable("AccessPolicy", (string)null); + + b.HasDiscriminator("Discriminator").HasValue("AccessPolicy"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ApiKey", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ClientSecret") + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("EncryptedPayload") + .HasMaxLength(4000) + .HasColumnType("character varying(4000)"); + + b.Property("ExpireAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Key") + .HasColumnType("text"); + + b.Property("Name") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Scope") + .HasMaxLength(4000) + .HasColumnType("character varying(4000)"); + + b.Property("ServiceAccountId") + .HasColumnType("uuid"); + + b.HasKey("Id") + .HasAnnotation("SqlServer:Clustered", true); + + b.HasIndex("ServiceAccountId") + .HasAnnotation("SqlServer:Clustered", false); + + b.ToTable("ApiKey", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Project", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("DeletedDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id") + .HasAnnotation("SqlServer:Clustered", true); + + b.HasIndex("DeletedDate") + .HasAnnotation("SqlServer:Clustered", false); + + b.HasIndex("OrganizationId") + .HasAnnotation("SqlServer:Clustered", false); + + b.ToTable("Project", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Secret", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("DeletedDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Key") + .HasColumnType("text"); + + b.Property("Note") + .HasColumnType("text"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Value") + .HasColumnType("text"); + + b.HasKey("Id") + .HasAnnotation("SqlServer:Clustered", true); + + b.HasIndex("DeletedDate") + .HasAnnotation("SqlServer:Clustered", false); + + b.HasIndex("OrganizationId") + .HasAnnotation("SqlServer:Clustered", false); + + b.ToTable("Secret", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccount", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id") + .HasAnnotation("SqlServer:Clustered", true); + + b.HasIndex("OrganizationId") + .HasAnnotation("SqlServer:Clustered", false); + + b.ToTable("ServiceAccount", (string)null); + }); + + modelBuilder.Entity("ProjectSecret", b => + { + b.Property("ProjectsId") + .HasColumnType("uuid"); + + b.Property("SecretsId") + .HasColumnType("uuid"); + + b.HasKey("ProjectsId", "SecretsId"); + + b.HasIndex("SecretsId"); + + b.ToTable("ProjectSecret"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.GroupProjectAccessPolicy", b => + { + b.HasBaseType("Bit.Infrastructure.EntityFramework.SecretsManager.Models.AccessPolicy"); + + b.Property("GrantedProjectId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("uuid") + .HasColumnName("GrantedProjectId"); + + b.Property("GroupId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("uuid") + .HasColumnName("GroupId"); + + b.HasIndex("GrantedProjectId"); + + b.HasIndex("GroupId"); + + b.HasDiscriminator().HasValue("group_project"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.GroupServiceAccountAccessPolicy", b => + { + b.HasBaseType("Bit.Infrastructure.EntityFramework.SecretsManager.Models.AccessPolicy"); + + b.Property("GrantedServiceAccountId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("uuid") + .HasColumnName("GrantedServiceAccountId"); + + b.Property("GroupId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("uuid") + .HasColumnName("GroupId"); + + b.HasIndex("GrantedServiceAccountId"); + + b.HasIndex("GroupId"); + + b.HasDiscriminator().HasValue("group_service_account"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccountProjectAccessPolicy", b => + { + b.HasBaseType("Bit.Infrastructure.EntityFramework.SecretsManager.Models.AccessPolicy"); + + b.Property("GrantedProjectId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("uuid") + .HasColumnName("GrantedProjectId"); + + b.Property("ServiceAccountId") + .HasColumnType("uuid") + .HasColumnName("ServiceAccountId"); + + b.HasIndex("GrantedProjectId"); + + b.HasIndex("ServiceAccountId"); + + b.HasDiscriminator().HasValue("service_account_project"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.UserProjectAccessPolicy", b => + { + b.HasBaseType("Bit.Infrastructure.EntityFramework.SecretsManager.Models.AccessPolicy"); + + b.Property("GrantedProjectId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("uuid") + .HasColumnName("GrantedProjectId"); + + b.Property("OrganizationUserId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("uuid") + .HasColumnName("OrganizationUserId"); + + b.HasIndex("GrantedProjectId"); + + b.HasIndex("OrganizationUserId"); + + b.HasDiscriminator().HasValue("user_project"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.UserServiceAccountAccessPolicy", b => + { + b.HasBaseType("Bit.Infrastructure.EntityFramework.SecretsManager.Models.AccessPolicy"); + + b.Property("GrantedServiceAccountId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("uuid") + .HasColumnName("GrantedServiceAccountId"); + + b.Property("OrganizationUserId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("uuid") + .HasColumnName("OrganizationUserId"); + + b.HasIndex("GrantedServiceAccountId"); + + b.HasIndex("OrganizationUserId"); + + b.HasDiscriminator().HasValue("user_service_account"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.AuthRequest", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Device", "ResponseDevice") + .WithMany() + .HasForeignKey("ResponseDeviceId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ResponseDevice"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Cipher", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Ciphers") + .HasForeignKey("OrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("Ciphers") + .HasForeignKey("UserId"); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Collection", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionCipher", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Cipher", "Cipher") + .WithMany("CollectionCiphers") + .HasForeignKey("CipherId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Collection", "Collection") + .WithMany("CollectionCiphers") + .HasForeignKey("CollectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Cipher"); + + b.Navigation("Collection"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionGroup", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Collection", "Collection") + .WithMany("CollectionGroups") + .HasForeignKey("CollectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Group", "Group") + .WithMany() + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Collection"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Collection", "Collection") + .WithMany("CollectionUsers") + .HasForeignKey("CollectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", "OrganizationUser") + .WithMany("CollectionUsers") + .HasForeignKey("OrganizationUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Collection"); + + b.Navigation("OrganizationUser"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Device", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.EmergencyAccess", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "Grantee") + .WithMany() + .HasForeignKey("GranteeId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "Grantor") + .WithMany() + .HasForeignKey("GrantorId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Grantee"); + + b.Navigation("Grantor"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Folder", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("Folders") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Group", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Groups") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.GroupUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Group", "Group") + .WithMany("GroupUsers") + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", "OrganizationUser") + .WithMany("GroupUsers") + .HasForeignKey("OrganizationUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Group"); + + b.Navigation("OrganizationUser"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationApiKey", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("ApiKeys") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationConnection", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Connections") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationSponsorship", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "SponsoredOrganization") + .WithMany() + .HasForeignKey("SponsoredOrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "SponsoringOrganization") + .WithMany() + .HasForeignKey("SponsoringOrganizationId"); + + b.Navigation("SponsoredOrganization"); + + b.Navigation("SponsoringOrganization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("OrganizationUsers") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("OrganizationUsers") + .HasForeignKey("UserId"); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Policy", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Policies") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderOrganization", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Provider", "Provider") + .WithMany() + .HasForeignKey("ProviderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + + b.Navigation("Provider"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Provider", "Provider") + .WithMany() + .HasForeignKey("ProviderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany() + .HasForeignKey("UserId"); + + b.Navigation("Provider"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Send", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany() + .HasForeignKey("UserId"); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoConfig", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("SsoConfigs") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("SsoUsers") + .HasForeignKey("OrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("SsoUsers") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Transaction", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Transactions") + .HasForeignKey("OrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("Transactions") + .HasForeignKey("UserId"); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ApiKey", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccount", "ServiceAccount") + .WithMany() + .HasForeignKey("ServiceAccountId"); + + b.Navigation("ServiceAccount"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Project", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Secret", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccount", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("ProjectSecret", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Project", null) + .WithMany() + .HasForeignKey("ProjectsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Secret", null) + .WithMany() + .HasForeignKey("SecretsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.GroupProjectAccessPolicy", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Project", "GrantedProject") + .WithMany("GroupAccessPolicies") + .HasForeignKey("GrantedProjectId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Group", "Group") + .WithMany() + .HasForeignKey("GroupId"); + + b.Navigation("GrantedProject"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.GroupServiceAccountAccessPolicy", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccount", "GrantedServiceAccount") + .WithMany("GroupAccessPolicies") + .HasForeignKey("GrantedServiceAccountId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Group", "Group") + .WithMany() + .HasForeignKey("GroupId"); + + b.Navigation("GrantedServiceAccount"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccountProjectAccessPolicy", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Project", "GrantedProject") + .WithMany("ServiceAccountAccessPolicies") + .HasForeignKey("GrantedProjectId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccount", "ServiceAccount") + .WithMany() + .HasForeignKey("ServiceAccountId"); + + b.Navigation("GrantedProject"); + + b.Navigation("ServiceAccount"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.UserProjectAccessPolicy", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Project", "GrantedProject") + .WithMany("UserAccessPolicies") + .HasForeignKey("GrantedProjectId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", "OrganizationUser") + .WithMany() + .HasForeignKey("OrganizationUserId"); + + b.Navigation("GrantedProject"); + + b.Navigation("OrganizationUser"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.UserServiceAccountAccessPolicy", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccount", "GrantedServiceAccount") + .WithMany("UserAccessPolicies") + .HasForeignKey("GrantedServiceAccountId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", "OrganizationUser") + .WithMany() + .HasForeignKey("OrganizationUserId"); + + b.Navigation("GrantedServiceAccount"); + + b.Navigation("OrganizationUser"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Cipher", b => + { + b.Navigation("CollectionCiphers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Collection", b => + { + b.Navigation("CollectionCiphers"); + + b.Navigation("CollectionGroups"); + + b.Navigation("CollectionUsers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Group", b => + { + b.Navigation("GroupUsers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Organization", b => + { + b.Navigation("ApiKeys"); + + b.Navigation("Ciphers"); + + b.Navigation("Connections"); + + b.Navigation("Groups"); + + b.Navigation("OrganizationUsers"); + + b.Navigation("Policies"); + + b.Navigation("SsoConfigs"); + + b.Navigation("SsoUsers"); + + b.Navigation("Transactions"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", b => + { + b.Navigation("CollectionUsers"); + + b.Navigation("GroupUsers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.User", b => + { + b.Navigation("Ciphers"); + + b.Navigation("Folders"); + + b.Navigation("OrganizationUsers"); + + b.Navigation("SsoUsers"); + + b.Navigation("Transactions"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Project", b => + { + b.Navigation("GroupAccessPolicies"); + + b.Navigation("ServiceAccountAccessPolicies"); + + b.Navigation("UserAccessPolicies"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccount", b => + { + b.Navigation("GroupAccessPolicies"); + + b.Navigation("UserAccessPolicies"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/util/PostgresMigrations/Migrations/20230201175207_SecretsManagerOrganizationUser.cs b/util/PostgresMigrations/Migrations/20230201175207_SecretsManagerOrganizationUser.cs new file mode 100644 index 0000000000..68b9698df1 --- /dev/null +++ b/util/PostgresMigrations/Migrations/20230201175207_SecretsManagerOrganizationUser.cs @@ -0,0 +1,25 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Bit.PostgresMigrations.Migrations; + +public partial class SecretsManagerOrganizationUser : Migration +{ + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "AccessSecretsManager", + table: "OrganizationUser", + type: "boolean", + nullable: false, + defaultValue: false); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "AccessSecretsManager", + table: "OrganizationUser"); + } +} diff --git a/util/PostgresMigrations/Migrations/20230201192558_LastUserDates.Designer.cs b/util/PostgresMigrations/Migrations/20230201192558_LastUserDates.Designer.cs new file mode 100644 index 0000000000..10c9833f6f --- /dev/null +++ b/util/PostgresMigrations/Migrations/20230201192558_LastUserDates.Designer.cs @@ -0,0 +1,2143 @@ +// +using System; +using Bit.Infrastructure.EntityFramework.Repositories; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace Bit.PostgresMigrations.Migrations +{ + [DbContext(typeof(DatabaseContext))] + [Migration("20230201192558_LastUserDates")] + partial class LastUserDates + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("Npgsql:CollationDefinition:postgresIndetermanisticCollation", "en-u-ks-primary,en-u-ks-primary,icu,False") + .HasAnnotation("ProductVersion", "6.0.12") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.AuthRequest", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AccessCode") + .HasMaxLength(25) + .HasColumnType("character varying(25)"); + + b.Property("Approved") + .HasColumnType("boolean"); + + b.Property("AuthenticationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Key") + .HasColumnType("text"); + + b.Property("MasterPasswordHash") + .HasColumnType("text"); + + b.Property("PublicKey") + .HasColumnType("text"); + + b.Property("RequestDeviceIdentifier") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("RequestDeviceType") + .HasColumnType("smallint"); + + b.Property("RequestFingerprint") + .HasColumnType("text"); + + b.Property("RequestIpAddress") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("ResponseDate") + .HasColumnType("timestamp with time zone"); + + b.Property("ResponseDeviceId") + .HasColumnType("uuid"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("ResponseDeviceId"); + + b.HasIndex("UserId"); + + b.ToTable("AuthRequest", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Cipher", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Attachments") + .HasColumnType("text"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Data") + .HasColumnType("text"); + + b.Property("DeletedDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Favorites") + .HasColumnType("text"); + + b.Property("Folders") + .HasColumnType("text"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("Reprompt") + .HasColumnType("smallint"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("Cipher", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Collection", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("ExternalId") + .HasMaxLength(300) + .HasColumnType("character varying(300)"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("Collection", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionCipher", b => + { + b.Property("CollectionId") + .HasColumnType("uuid"); + + b.Property("CipherId") + .HasColumnType("uuid"); + + b.HasKey("CollectionId", "CipherId"); + + b.HasIndex("CipherId"); + + b.ToTable("CollectionCipher", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionGroup", b => + { + b.Property("CollectionId") + .HasColumnType("uuid"); + + b.Property("GroupId") + .HasColumnType("uuid"); + + b.Property("HidePasswords") + .HasColumnType("boolean"); + + b.Property("ReadOnly") + .HasColumnType("boolean"); + + b.HasKey("CollectionId", "GroupId"); + + b.HasIndex("GroupId"); + + b.ToTable("CollectionGroups"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionUser", b => + { + b.Property("CollectionId") + .HasColumnType("uuid"); + + b.Property("OrganizationUserId") + .HasColumnType("uuid"); + + b.Property("HidePasswords") + .HasColumnType("boolean"); + + b.Property("ReadOnly") + .HasColumnType("boolean"); + + b.HasKey("CollectionId", "OrganizationUserId"); + + b.HasIndex("OrganizationUserId"); + + b.ToTable("CollectionUsers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Device", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Identifier") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Name") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("PushToken") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("Device", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.EmergencyAccess", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("GranteeId") + .HasColumnType("uuid"); + + b.Property("GrantorId") + .HasColumnType("uuid"); + + b.Property("KeyEncrypted") + .HasColumnType("text"); + + b.Property("LastNotificationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("RecoveryInitiatedDate") + .HasColumnType("timestamp with time zone"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Status") + .HasColumnType("smallint"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.Property("WaitTimeDays") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("GranteeId"); + + b.HasIndex("GrantorId"); + + b.ToTable("EmergencyAccess", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Event", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ActingUserId") + .HasColumnType("uuid"); + + b.Property("CipherId") + .HasColumnType("uuid"); + + b.Property("CollectionId") + .HasColumnType("uuid"); + + b.Property("Date") + .HasColumnType("timestamp with time zone"); + + b.Property("DeviceType") + .HasColumnType("smallint"); + + b.Property("GroupId") + .HasColumnType("uuid"); + + b.Property("InstallationId") + .HasColumnType("uuid"); + + b.Property("IpAddress") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("OrganizationUserId") + .HasColumnType("uuid"); + + b.Property("PolicyId") + .HasColumnType("uuid"); + + b.Property("ProviderId") + .HasColumnType("uuid"); + + b.Property("ProviderOrganizationId") + .HasColumnType("uuid"); + + b.Property("ProviderUserId") + .HasColumnType("uuid"); + + b.Property("SystemUser") + .HasColumnType("smallint"); + + b.Property("Type") + .HasColumnType("integer"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.ToTable("Event", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Folder", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("Folder", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Grant", b => + { + b.Property("Key") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ClientId") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ConsumedDate") + .HasColumnType("timestamp with time zone"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Data") + .HasColumnType("text"); + + b.Property("Description") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("ExpirationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("SessionId") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("SubjectId") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("Type") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.HasKey("Key"); + + b.ToTable("Grant", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Group", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AccessAll") + .HasColumnType("boolean"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("ExternalId") + .HasMaxLength(300) + .HasColumnType("character varying(300)"); + + b.Property("Name") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("Group", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.GroupUser", b => + { + b.Property("GroupId") + .HasColumnType("uuid"); + + b.Property("OrganizationUserId") + .HasColumnType("uuid"); + + b.HasKey("GroupId", "OrganizationUserId"); + + b.HasIndex("OrganizationUserId"); + + b.ToTable("GroupUser", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Installation", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("Key") + .HasMaxLength(150) + .HasColumnType("character varying(150)"); + + b.HasKey("Id"); + + b.ToTable("Installation", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Organization", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("BillingEmail") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("BusinessAddress1") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("BusinessAddress2") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("BusinessAddress3") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("BusinessCountry") + .HasMaxLength(2) + .HasColumnType("character varying(2)"); + + b.Property("BusinessName") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("BusinessTaxNumber") + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("ExpirationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Gateway") + .HasColumnType("smallint"); + + b.Property("GatewayCustomerId") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("GatewaySubscriptionId") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Identifier") + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .UseCollation("postgresIndetermanisticCollation"); + + b.Property("LicenseKey") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("MaxAutoscaleSeats") + .HasColumnType("integer"); + + b.Property("MaxCollections") + .HasColumnType("smallint"); + + b.Property("MaxStorageGb") + .HasColumnType("smallint"); + + b.Property("Name") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("OwnersNotifiedOfAutoscaling") + .HasColumnType("timestamp with time zone"); + + b.Property("Plan") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("PlanType") + .HasColumnType("smallint"); + + b.Property("PrivateKey") + .HasColumnType("text"); + + b.Property("PublicKey") + .HasColumnType("text"); + + b.Property("ReferenceData") + .HasColumnType("text"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Seats") + .HasColumnType("integer"); + + b.Property("SelfHost") + .HasColumnType("boolean"); + + b.Property("Storage") + .HasColumnType("bigint"); + + b.Property("TwoFactorProviders") + .HasColumnType("text"); + + b.Property("Use2fa") + .HasColumnType("boolean"); + + b.Property("UseApi") + .HasColumnType("boolean"); + + b.Property("UseCustomPermissions") + .HasColumnType("boolean"); + + b.Property("UseDirectory") + .HasColumnType("boolean"); + + b.Property("UseEvents") + .HasColumnType("boolean"); + + b.Property("UseGroups") + .HasColumnType("boolean"); + + b.Property("UseKeyConnector") + .HasColumnType("boolean"); + + b.Property("UsePolicies") + .HasColumnType("boolean"); + + b.Property("UseResetPassword") + .HasColumnType("boolean"); + + b.Property("UseScim") + .HasColumnType("boolean"); + + b.Property("UseSecretsManager") + .HasColumnType("boolean"); + + b.Property("UseSso") + .HasColumnType("boolean"); + + b.Property("UseTotp") + .HasColumnType("boolean"); + + b.Property("UsersGetPremium") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.ToTable("Organization", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationApiKey", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ApiKey") + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("OrganizationApiKey", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationConnection", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Config") + .HasColumnType("text"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("OrganizationConnection", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationSponsorship", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("FriendlyName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("LastSyncDate") + .HasColumnType("timestamp with time zone"); + + b.Property("OfferedToEmail") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("PlanSponsorshipType") + .HasColumnType("smallint"); + + b.Property("SponsoredOrganizationId") + .HasColumnType("uuid"); + + b.Property("SponsoringOrganizationId") + .HasColumnType("uuid"); + + b.Property("SponsoringOrganizationUserId") + .HasColumnType("uuid"); + + b.Property("ToDelete") + .HasColumnType("boolean"); + + b.Property("ValidUntil") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("SponsoredOrganizationId"); + + b.HasIndex("SponsoringOrganizationId"); + + b.ToTable("OrganizationSponsorship", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AccessAll") + .HasColumnType("boolean"); + + b.Property("AccessSecretsManager") + .HasColumnType("boolean"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("ExternalId") + .HasMaxLength(300) + .HasColumnType("character varying(300)"); + + b.Property("Key") + .HasColumnType("text"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("Permissions") + .HasColumnType("text"); + + b.Property("ResetPasswordKey") + .HasColumnType("text"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Status") + .HasColumnType("smallint"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("OrganizationUser", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Policy", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Data") + .HasColumnType("text"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("Policy", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Provider", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("BillingEmail") + .HasColumnType("text"); + + b.Property("BillingPhone") + .HasColumnType("text"); + + b.Property("BusinessAddress1") + .HasColumnType("text"); + + b.Property("BusinessAddress2") + .HasColumnType("text"); + + b.Property("BusinessAddress3") + .HasColumnType("text"); + + b.Property("BusinessCountry") + .HasColumnType("text"); + + b.Property("BusinessName") + .HasColumnType("text"); + + b.Property("BusinessTaxNumber") + .HasColumnType("text"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Status") + .HasColumnType("smallint"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.Property("UseEvents") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.ToTable("Provider", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderOrganization", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Key") + .HasColumnType("text"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("ProviderId") + .HasColumnType("uuid"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Settings") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("ProviderId"); + + b.ToTable("ProviderOrganization", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderUser", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Email") + .HasColumnType("text"); + + b.Property("Key") + .HasColumnType("text"); + + b.Property("Permissions") + .HasColumnType("text"); + + b.Property("ProviderId") + .HasColumnType("uuid"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Status") + .HasColumnType("smallint"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("ProviderId"); + + b.HasIndex("UserId"); + + b.ToTable("ProviderUser", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Send", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AccessCount") + .HasColumnType("integer"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Data") + .HasColumnType("text"); + + b.Property("DeletionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Disabled") + .HasColumnType("boolean"); + + b.Property("ExpirationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("HideEmail") + .HasColumnType("boolean"); + + b.Property("Key") + .HasColumnType("text"); + + b.Property("MaxAccessCount") + .HasColumnType("integer"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("Password") + .HasMaxLength(300) + .HasColumnType("character varying(300)"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("Send", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Data") + .HasColumnType("text"); + + b.Property("Enabled") + .HasColumnType("boolean"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("SsoConfig", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("ExternalId") + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .UseCollation("postgresIndetermanisticCollation"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("SsoUser", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.TaxRate", b => + { + b.Property("Id") + .HasMaxLength(40) + .HasColumnType("character varying(40)"); + + b.Property("Active") + .HasColumnType("boolean"); + + b.Property("Country") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("PostalCode") + .HasMaxLength(10) + .HasColumnType("character varying(10)"); + + b.Property("Rate") + .HasColumnType("numeric"); + + b.Property("State") + .HasMaxLength(2) + .HasColumnType("character varying(2)"); + + b.HasKey("Id"); + + b.ToTable("TaxRate", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Transaction", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Amount") + .HasColumnType("numeric"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Details") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("Gateway") + .HasColumnType("smallint"); + + b.Property("GatewayId") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("PaymentMethodType") + .HasColumnType("smallint"); + + b.Property("Refunded") + .HasColumnType("boolean"); + + b.Property("RefundedAmount") + .HasColumnType("numeric"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("Transaction", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.User", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("AccountRevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("ApiKey") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("AvatarColor") + .HasMaxLength(7) + .HasColumnType("character varying(7)"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Culture") + .HasMaxLength(10) + .HasColumnType("character varying(10)"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .UseCollation("postgresIndetermanisticCollation"); + + b.Property("EmailVerified") + .HasColumnType("boolean"); + + b.Property("EquivalentDomains") + .HasColumnType("text"); + + b.Property("ExcludedGlobalEquivalentDomains") + .HasColumnType("text"); + + b.Property("FailedLoginCount") + .HasColumnType("integer"); + + b.Property("ForcePasswordReset") + .HasColumnType("boolean"); + + b.Property("Gateway") + .HasColumnType("smallint"); + + b.Property("GatewayCustomerId") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("GatewaySubscriptionId") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Kdf") + .HasColumnType("smallint"); + + b.Property("KdfIterations") + .HasColumnType("integer"); + + b.Property("KdfMemory") + .HasColumnType("integer"); + + b.Property("KdfParallelism") + .HasColumnType("integer"); + + b.Property("Key") + .HasColumnType("text"); + + b.Property("LastEmailChangeDate") + .HasColumnType("timestamp with time zone"); + + b.Property("LastFailedLoginDate") + .HasColumnType("timestamp with time zone"); + + b.Property("LastKdfChangeDate") + .HasColumnType("timestamp with time zone"); + + b.Property("LastKeyRotationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("LastPasswordChangeDate") + .HasColumnType("timestamp with time zone"); + + b.Property("LicenseKey") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("MasterPassword") + .HasMaxLength(300) + .HasColumnType("character varying(300)"); + + b.Property("MasterPasswordHint") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("MaxStorageGb") + .HasColumnType("smallint"); + + b.Property("Name") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Premium") + .HasColumnType("boolean"); + + b.Property("PremiumExpirationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("PrivateKey") + .HasColumnType("text"); + + b.Property("PublicKey") + .HasColumnType("text"); + + b.Property("ReferenceData") + .HasColumnType("text"); + + b.Property("RenewalReminderDate") + .HasColumnType("timestamp with time zone"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("SecurityStamp") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Storage") + .HasColumnType("bigint"); + + b.Property("TwoFactorProviders") + .HasColumnType("text"); + + b.Property("TwoFactorRecoveryCode") + .HasMaxLength(32) + .HasColumnType("character varying(32)"); + + b.Property("UnknownDeviceVerificationEnabled") + .HasColumnType("boolean"); + + b.Property("UsesKeyConnector") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.ToTable("User", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.AccessPolicy", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Discriminator") + .IsRequired() + .HasColumnType("text"); + + b.Property("Read") + .HasColumnType("boolean"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Write") + .HasColumnType("boolean"); + + b.HasKey("Id") + .HasAnnotation("SqlServer:Clustered", true); + + b.ToTable("AccessPolicy", (string)null); + + b.HasDiscriminator("Discriminator").HasValue("AccessPolicy"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ApiKey", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ClientSecret") + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("EncryptedPayload") + .HasMaxLength(4000) + .HasColumnType("character varying(4000)"); + + b.Property("ExpireAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Key") + .HasColumnType("text"); + + b.Property("Name") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Scope") + .HasMaxLength(4000) + .HasColumnType("character varying(4000)"); + + b.Property("ServiceAccountId") + .HasColumnType("uuid"); + + b.HasKey("Id") + .HasAnnotation("SqlServer:Clustered", true); + + b.HasIndex("ServiceAccountId") + .HasAnnotation("SqlServer:Clustered", false); + + b.ToTable("ApiKey", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Project", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("DeletedDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id") + .HasAnnotation("SqlServer:Clustered", true); + + b.HasIndex("DeletedDate") + .HasAnnotation("SqlServer:Clustered", false); + + b.HasIndex("OrganizationId") + .HasAnnotation("SqlServer:Clustered", false); + + b.ToTable("Project", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Secret", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("DeletedDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Key") + .HasColumnType("text"); + + b.Property("Note") + .HasColumnType("text"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Value") + .HasColumnType("text"); + + b.HasKey("Id") + .HasAnnotation("SqlServer:Clustered", true); + + b.HasIndex("DeletedDate") + .HasAnnotation("SqlServer:Clustered", false); + + b.HasIndex("OrganizationId") + .HasAnnotation("SqlServer:Clustered", false); + + b.ToTable("Secret", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccount", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id") + .HasAnnotation("SqlServer:Clustered", true); + + b.HasIndex("OrganizationId") + .HasAnnotation("SqlServer:Clustered", false); + + b.ToTable("ServiceAccount", (string)null); + }); + + modelBuilder.Entity("ProjectSecret", b => + { + b.Property("ProjectsId") + .HasColumnType("uuid"); + + b.Property("SecretsId") + .HasColumnType("uuid"); + + b.HasKey("ProjectsId", "SecretsId"); + + b.HasIndex("SecretsId"); + + b.ToTable("ProjectSecret"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.GroupProjectAccessPolicy", b => + { + b.HasBaseType("Bit.Infrastructure.EntityFramework.SecretsManager.Models.AccessPolicy"); + + b.Property("GrantedProjectId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("uuid") + .HasColumnName("GrantedProjectId"); + + b.Property("GroupId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("uuid") + .HasColumnName("GroupId"); + + b.HasIndex("GrantedProjectId"); + + b.HasIndex("GroupId"); + + b.HasDiscriminator().HasValue("group_project"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.GroupServiceAccountAccessPolicy", b => + { + b.HasBaseType("Bit.Infrastructure.EntityFramework.SecretsManager.Models.AccessPolicy"); + + b.Property("GrantedServiceAccountId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("uuid") + .HasColumnName("GrantedServiceAccountId"); + + b.Property("GroupId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("uuid") + .HasColumnName("GroupId"); + + b.HasIndex("GrantedServiceAccountId"); + + b.HasIndex("GroupId"); + + b.HasDiscriminator().HasValue("group_service_account"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccountProjectAccessPolicy", b => + { + b.HasBaseType("Bit.Infrastructure.EntityFramework.SecretsManager.Models.AccessPolicy"); + + b.Property("GrantedProjectId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("uuid") + .HasColumnName("GrantedProjectId"); + + b.Property("ServiceAccountId") + .HasColumnType("uuid") + .HasColumnName("ServiceAccountId"); + + b.HasIndex("GrantedProjectId"); + + b.HasIndex("ServiceAccountId"); + + b.HasDiscriminator().HasValue("service_account_project"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.UserProjectAccessPolicy", b => + { + b.HasBaseType("Bit.Infrastructure.EntityFramework.SecretsManager.Models.AccessPolicy"); + + b.Property("GrantedProjectId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("uuid") + .HasColumnName("GrantedProjectId"); + + b.Property("OrganizationUserId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("uuid") + .HasColumnName("OrganizationUserId"); + + b.HasIndex("GrantedProjectId"); + + b.HasIndex("OrganizationUserId"); + + b.HasDiscriminator().HasValue("user_project"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.UserServiceAccountAccessPolicy", b => + { + b.HasBaseType("Bit.Infrastructure.EntityFramework.SecretsManager.Models.AccessPolicy"); + + b.Property("GrantedServiceAccountId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("uuid") + .HasColumnName("GrantedServiceAccountId"); + + b.Property("OrganizationUserId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("uuid") + .HasColumnName("OrganizationUserId"); + + b.HasIndex("GrantedServiceAccountId"); + + b.HasIndex("OrganizationUserId"); + + b.HasDiscriminator().HasValue("user_service_account"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.AuthRequest", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Device", "ResponseDevice") + .WithMany() + .HasForeignKey("ResponseDeviceId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ResponseDevice"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Cipher", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Ciphers") + .HasForeignKey("OrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("Ciphers") + .HasForeignKey("UserId"); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Collection", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionCipher", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Cipher", "Cipher") + .WithMany("CollectionCiphers") + .HasForeignKey("CipherId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Collection", "Collection") + .WithMany("CollectionCiphers") + .HasForeignKey("CollectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Cipher"); + + b.Navigation("Collection"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionGroup", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Collection", "Collection") + .WithMany("CollectionGroups") + .HasForeignKey("CollectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Group", "Group") + .WithMany() + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Collection"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Collection", "Collection") + .WithMany("CollectionUsers") + .HasForeignKey("CollectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", "OrganizationUser") + .WithMany("CollectionUsers") + .HasForeignKey("OrganizationUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Collection"); + + b.Navigation("OrganizationUser"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Device", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.EmergencyAccess", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "Grantee") + .WithMany() + .HasForeignKey("GranteeId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "Grantor") + .WithMany() + .HasForeignKey("GrantorId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Grantee"); + + b.Navigation("Grantor"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Folder", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("Folders") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Group", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Groups") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.GroupUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Group", "Group") + .WithMany("GroupUsers") + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", "OrganizationUser") + .WithMany("GroupUsers") + .HasForeignKey("OrganizationUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Group"); + + b.Navigation("OrganizationUser"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationApiKey", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("ApiKeys") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationConnection", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Connections") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationSponsorship", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "SponsoredOrganization") + .WithMany() + .HasForeignKey("SponsoredOrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "SponsoringOrganization") + .WithMany() + .HasForeignKey("SponsoringOrganizationId"); + + b.Navigation("SponsoredOrganization"); + + b.Navigation("SponsoringOrganization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("OrganizationUsers") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("OrganizationUsers") + .HasForeignKey("UserId"); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Policy", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Policies") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderOrganization", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Provider", "Provider") + .WithMany() + .HasForeignKey("ProviderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + + b.Navigation("Provider"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Provider", "Provider") + .WithMany() + .HasForeignKey("ProviderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany() + .HasForeignKey("UserId"); + + b.Navigation("Provider"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Send", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany() + .HasForeignKey("UserId"); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoConfig", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("SsoConfigs") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("SsoUsers") + .HasForeignKey("OrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("SsoUsers") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Transaction", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Transactions") + .HasForeignKey("OrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("Transactions") + .HasForeignKey("UserId"); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ApiKey", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccount", "ServiceAccount") + .WithMany() + .HasForeignKey("ServiceAccountId"); + + b.Navigation("ServiceAccount"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Project", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Secret", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccount", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("ProjectSecret", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Project", null) + .WithMany() + .HasForeignKey("ProjectsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Secret", null) + .WithMany() + .HasForeignKey("SecretsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.GroupProjectAccessPolicy", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Project", "GrantedProject") + .WithMany("GroupAccessPolicies") + .HasForeignKey("GrantedProjectId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Group", "Group") + .WithMany() + .HasForeignKey("GroupId"); + + b.Navigation("GrantedProject"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.GroupServiceAccountAccessPolicy", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccount", "GrantedServiceAccount") + .WithMany("GroupAccessPolicies") + .HasForeignKey("GrantedServiceAccountId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Group", "Group") + .WithMany() + .HasForeignKey("GroupId"); + + b.Navigation("GrantedServiceAccount"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccountProjectAccessPolicy", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Project", "GrantedProject") + .WithMany("ServiceAccountAccessPolicies") + .HasForeignKey("GrantedProjectId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccount", "ServiceAccount") + .WithMany() + .HasForeignKey("ServiceAccountId"); + + b.Navigation("GrantedProject"); + + b.Navigation("ServiceAccount"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.UserProjectAccessPolicy", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Project", "GrantedProject") + .WithMany("UserAccessPolicies") + .HasForeignKey("GrantedProjectId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", "OrganizationUser") + .WithMany() + .HasForeignKey("OrganizationUserId"); + + b.Navigation("GrantedProject"); + + b.Navigation("OrganizationUser"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.UserServiceAccountAccessPolicy", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccount", "GrantedServiceAccount") + .WithMany("UserAccessPolicies") + .HasForeignKey("GrantedServiceAccountId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", "OrganizationUser") + .WithMany() + .HasForeignKey("OrganizationUserId"); + + b.Navigation("GrantedServiceAccount"); + + b.Navigation("OrganizationUser"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Cipher", b => + { + b.Navigation("CollectionCiphers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Collection", b => + { + b.Navigation("CollectionCiphers"); + + b.Navigation("CollectionGroups"); + + b.Navigation("CollectionUsers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Group", b => + { + b.Navigation("GroupUsers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Organization", b => + { + b.Navigation("ApiKeys"); + + b.Navigation("Ciphers"); + + b.Navigation("Connections"); + + b.Navigation("Groups"); + + b.Navigation("OrganizationUsers"); + + b.Navigation("Policies"); + + b.Navigation("SsoConfigs"); + + b.Navigation("SsoUsers"); + + b.Navigation("Transactions"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", b => + { + b.Navigation("CollectionUsers"); + + b.Navigation("GroupUsers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.User", b => + { + b.Navigation("Ciphers"); + + b.Navigation("Folders"); + + b.Navigation("OrganizationUsers"); + + b.Navigation("SsoUsers"); + + b.Navigation("Transactions"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Project", b => + { + b.Navigation("GroupAccessPolicies"); + + b.Navigation("ServiceAccountAccessPolicies"); + + b.Navigation("UserAccessPolicies"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccount", b => + { + b.Navigation("GroupAccessPolicies"); + + b.Navigation("UserAccessPolicies"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/util/PostgresMigrations/Migrations/20230201192558_LastUserDates.cs b/util/PostgresMigrations/Migrations/20230201192558_LastUserDates.cs new file mode 100644 index 0000000000..ed3d344f11 --- /dev/null +++ b/util/PostgresMigrations/Migrations/20230201192558_LastUserDates.cs @@ -0,0 +1,54 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Bit.PostgresMigrations.Migrations; + +public partial class LastUserDates : Migration +{ + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "LastEmailChangeDate", + table: "User", + type: "timestamp with time zone", + nullable: true); + + migrationBuilder.AddColumn( + name: "LastKdfChangeDate", + table: "User", + type: "timestamp with time zone", + nullable: true); + + migrationBuilder.AddColumn( + name: "LastKeyRotationDate", + table: "User", + type: "timestamp with time zone", + nullable: true); + + migrationBuilder.AddColumn( + name: "LastPasswordChangeDate", + table: "User", + type: "timestamp with time zone", + nullable: true); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "LastEmailChangeDate", + table: "User"); + + migrationBuilder.DropColumn( + name: "LastKdfChangeDate", + table: "User"); + + migrationBuilder.DropColumn( + name: "LastKeyRotationDate", + table: "User"); + + migrationBuilder.DropColumn( + name: "LastPasswordChangeDate", + table: "User"); + } +} diff --git a/util/PostgresMigrations/Migrations/DatabaseContextModelSnapshot.cs b/util/PostgresMigrations/Migrations/DatabaseContextModelSnapshot.cs index 56cb67727a..5a11a8a4a7 100644 --- a/util/PostgresMigrations/Migrations/DatabaseContextModelSnapshot.cs +++ b/util/PostgresMigrations/Migrations/DatabaseContextModelSnapshot.cs @@ -23,80 +23,6 @@ namespace Bit.PostgresMigrations.Migrations NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.AccessPolicy", b => - { - b.Property("Id") - .HasColumnType("uuid"); - - b.Property("CreationDate") - .HasColumnType("timestamp with time zone"); - - b.Property("Discriminator") - .IsRequired() - .HasColumnType("text"); - - b.Property("Read") - .HasColumnType("boolean"); - - b.Property("RevisionDate") - .HasColumnType("timestamp with time zone"); - - b.Property("Write") - .HasColumnType("boolean"); - - b.HasKey("Id") - .HasAnnotation("SqlServer:Clustered", true); - - b.ToTable("AccessPolicy", (string)null); - - b.HasDiscriminator("Discriminator").HasValue("AccessPolicy"); - }); - - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ApiKey", b => - { - b.Property("Id") - .HasColumnType("uuid"); - - b.Property("ClientSecret") - .HasMaxLength(30) - .HasColumnType("character varying(30)"); - - b.Property("CreationDate") - .HasColumnType("timestamp with time zone"); - - b.Property("EncryptedPayload") - .HasMaxLength(4000) - .HasColumnType("character varying(4000)"); - - b.Property("ExpireAt") - .HasColumnType("timestamp with time zone"); - - b.Property("Key") - .HasColumnType("text"); - - b.Property("Name") - .HasMaxLength(200) - .HasColumnType("character varying(200)"); - - b.Property("RevisionDate") - .HasColumnType("timestamp with time zone"); - - b.Property("Scope") - .HasMaxLength(4000) - .HasColumnType("character varying(4000)"); - - b.Property("ServiceAccountId") - .HasColumnType("uuid"); - - b.HasKey("Id") - .HasAnnotation("SqlServer:Clustered", true); - - b.HasIndex("ServiceAccountId") - .HasAnnotation("SqlServer:Clustered", false); - - b.ToTable("ApiKey", (string)null); - }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.AuthRequest", b => { b.Property("Id") @@ -835,6 +761,9 @@ namespace Bit.PostgresMigrations.Migrations b.Property("AccessAll") .HasColumnType("boolean"); + b.Property("AccessSecretsManager") + .HasColumnType("boolean"); + b.Property("CreationDate") .HasColumnType("timestamp with time zone"); @@ -909,38 +838,6 @@ namespace Bit.PostgresMigrations.Migrations b.ToTable("Policy", (string)null); }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Project", b => - { - b.Property("Id") - .HasColumnType("uuid"); - - b.Property("CreationDate") - .HasColumnType("timestamp with time zone"); - - b.Property("DeletedDate") - .HasColumnType("timestamp with time zone"); - - b.Property("Name") - .HasColumnType("text"); - - b.Property("OrganizationId") - .HasColumnType("uuid"); - - b.Property("RevisionDate") - .HasColumnType("timestamp with time zone"); - - b.HasKey("Id") - .HasAnnotation("SqlServer:Clustered", true); - - b.HasIndex("DeletedDate") - .HasAnnotation("SqlServer:Clustered", false); - - b.HasIndex("OrganizationId") - .HasAnnotation("SqlServer:Clustered", false); - - b.ToTable("Project", (string)null); - }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Provider", b => { b.Property("Id") @@ -1069,44 +966,6 @@ namespace Bit.PostgresMigrations.Migrations b.ToTable("ProviderUser", (string)null); }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Secret", b => - { - b.Property("Id") - .HasColumnType("uuid"); - - b.Property("CreationDate") - .HasColumnType("timestamp with time zone"); - - b.Property("DeletedDate") - .HasColumnType("timestamp with time zone"); - - b.Property("Key") - .HasColumnType("text"); - - b.Property("Note") - .HasColumnType("text"); - - b.Property("OrganizationId") - .HasColumnType("uuid"); - - b.Property("RevisionDate") - .HasColumnType("timestamp with time zone"); - - b.Property("Value") - .HasColumnType("text"); - - b.HasKey("Id") - .HasAnnotation("SqlServer:Clustered", true); - - b.HasIndex("DeletedDate") - .HasAnnotation("SqlServer:Clustered", false); - - b.HasIndex("OrganizationId") - .HasAnnotation("SqlServer:Clustered", false); - - b.ToTable("Secret", (string)null); - }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Send", b => { b.Property("Id") @@ -1164,32 +1023,6 @@ namespace Bit.PostgresMigrations.Migrations b.ToTable("Send", (string)null); }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ServiceAccount", b => - { - b.Property("Id") - .HasColumnType("uuid"); - - b.Property("CreationDate") - .HasColumnType("timestamp with time zone"); - - b.Property("Name") - .HasColumnType("text"); - - b.Property("OrganizationId") - .HasColumnType("uuid"); - - b.Property("RevisionDate") - .HasColumnType("timestamp with time zone"); - - b.HasKey("Id") - .HasAnnotation("SqlServer:Clustered", true); - - b.HasIndex("OrganizationId") - .HasAnnotation("SqlServer:Clustered", false); - - b.ToTable("ServiceAccount", (string)null); - }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoConfig", b => { b.Property("Id") @@ -1400,9 +1233,21 @@ namespace Bit.PostgresMigrations.Migrations b.Property("Key") .HasColumnType("text"); + b.Property("LastEmailChangeDate") + .HasColumnType("timestamp with time zone"); + b.Property("LastFailedLoginDate") .HasColumnType("timestamp with time zone"); + b.Property("LastKdfChangeDate") + .HasColumnType("timestamp with time zone"); + + b.Property("LastKeyRotationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("LastPasswordChangeDate") + .HasColumnType("timestamp with time zone"); + b.Property("LicenseKey") .HasMaxLength(100) .HasColumnType("character varying(100)"); @@ -1469,6 +1314,176 @@ namespace Bit.PostgresMigrations.Migrations b.ToTable("User", (string)null); }); + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.AccessPolicy", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Discriminator") + .IsRequired() + .HasColumnType("text"); + + b.Property("Read") + .HasColumnType("boolean"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Write") + .HasColumnType("boolean"); + + b.HasKey("Id") + .HasAnnotation("SqlServer:Clustered", true); + + b.ToTable("AccessPolicy", (string)null); + + b.HasDiscriminator("Discriminator").HasValue("AccessPolicy"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ApiKey", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("ClientSecret") + .HasMaxLength(30) + .HasColumnType("character varying(30)"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("EncryptedPayload") + .HasMaxLength(4000) + .HasColumnType("character varying(4000)"); + + b.Property("ExpireAt") + .HasColumnType("timestamp with time zone"); + + b.Property("Key") + .HasColumnType("text"); + + b.Property("Name") + .HasMaxLength(200) + .HasColumnType("character varying(200)"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Scope") + .HasMaxLength(4000) + .HasColumnType("character varying(4000)"); + + b.Property("ServiceAccountId") + .HasColumnType("uuid"); + + b.HasKey("Id") + .HasAnnotation("SqlServer:Clustered", true); + + b.HasIndex("ServiceAccountId") + .HasAnnotation("SqlServer:Clustered", false); + + b.ToTable("ApiKey", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Project", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("DeletedDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id") + .HasAnnotation("SqlServer:Clustered", true); + + b.HasIndex("DeletedDate") + .HasAnnotation("SqlServer:Clustered", false); + + b.HasIndex("OrganizationId") + .HasAnnotation("SqlServer:Clustered", false); + + b.ToTable("Project", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Secret", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("DeletedDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Key") + .HasColumnType("text"); + + b.Property("Note") + .HasColumnType("text"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Value") + .HasColumnType("text"); + + b.HasKey("Id") + .HasAnnotation("SqlServer:Clustered", true); + + b.HasIndex("DeletedDate") + .HasAnnotation("SqlServer:Clustered", false); + + b.HasIndex("OrganizationId") + .HasAnnotation("SqlServer:Clustered", false); + + b.ToTable("Secret", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccount", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("OrganizationId") + .HasColumnType("uuid"); + + b.Property("RevisionDate") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id") + .HasAnnotation("SqlServer:Clustered", true); + + b.HasIndex("OrganizationId") + .HasAnnotation("SqlServer:Clustered", false); + + b.ToTable("ServiceAccount", (string)null); + }); + modelBuilder.Entity("ProjectSecret", b => { b.Property("ProjectsId") @@ -1484,9 +1499,9 @@ namespace Bit.PostgresMigrations.Migrations b.ToTable("ProjectSecret"); }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.GroupProjectAccessPolicy", b => + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.GroupProjectAccessPolicy", b => { - b.HasBaseType("Bit.Infrastructure.EntityFramework.Models.AccessPolicy"); + b.HasBaseType("Bit.Infrastructure.EntityFramework.SecretsManager.Models.AccessPolicy"); b.Property("GrantedProjectId") .ValueGeneratedOnUpdateSometimes() @@ -1505,9 +1520,9 @@ namespace Bit.PostgresMigrations.Migrations b.HasDiscriminator().HasValue("group_project"); }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.GroupServiceAccountAccessPolicy", b => + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.GroupServiceAccountAccessPolicy", b => { - b.HasBaseType("Bit.Infrastructure.EntityFramework.Models.AccessPolicy"); + b.HasBaseType("Bit.Infrastructure.EntityFramework.SecretsManager.Models.AccessPolicy"); b.Property("GrantedServiceAccountId") .ValueGeneratedOnUpdateSometimes() @@ -1526,9 +1541,9 @@ namespace Bit.PostgresMigrations.Migrations b.HasDiscriminator().HasValue("group_service_account"); }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ServiceAccountProjectAccessPolicy", b => + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccountProjectAccessPolicy", b => { - b.HasBaseType("Bit.Infrastructure.EntityFramework.Models.AccessPolicy"); + b.HasBaseType("Bit.Infrastructure.EntityFramework.SecretsManager.Models.AccessPolicy"); b.Property("GrantedProjectId") .ValueGeneratedOnUpdateSometimes() @@ -1546,9 +1561,9 @@ namespace Bit.PostgresMigrations.Migrations b.HasDiscriminator().HasValue("service_account_project"); }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.UserProjectAccessPolicy", b => + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.UserProjectAccessPolicy", b => { - b.HasBaseType("Bit.Infrastructure.EntityFramework.Models.AccessPolicy"); + b.HasBaseType("Bit.Infrastructure.EntityFramework.SecretsManager.Models.AccessPolicy"); b.Property("GrantedProjectId") .ValueGeneratedOnUpdateSometimes() @@ -1567,9 +1582,9 @@ namespace Bit.PostgresMigrations.Migrations b.HasDiscriminator().HasValue("user_project"); }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.UserServiceAccountAccessPolicy", b => + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.UserServiceAccountAccessPolicy", b => { - b.HasBaseType("Bit.Infrastructure.EntityFramework.Models.AccessPolicy"); + b.HasBaseType("Bit.Infrastructure.EntityFramework.SecretsManager.Models.AccessPolicy"); b.Property("GrantedServiceAccountId") .ValueGeneratedOnUpdateSometimes() @@ -1588,15 +1603,6 @@ namespace Bit.PostgresMigrations.Migrations b.HasDiscriminator().HasValue("user_service_account"); }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ApiKey", b => - { - b.HasOne("Bit.Infrastructure.EntityFramework.Models.ServiceAccount", "ServiceAccount") - .WithMany() - .HasForeignKey("ServiceAccountId"); - - b.Navigation("ServiceAccount"); - }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.AuthRequest", b => { b.HasOne("Bit.Infrastructure.EntityFramework.Models.Device", "ResponseDevice") @@ -1831,17 +1837,6 @@ namespace Bit.PostgresMigrations.Migrations b.Navigation("Organization"); }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Project", b => - { - b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") - .WithMany() - .HasForeignKey("OrganizationId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Organization"); - }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderOrganization", b => { b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") @@ -1878,17 +1873,6 @@ namespace Bit.PostgresMigrations.Migrations b.Navigation("User"); }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Secret", b => - { - b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") - .WithMany() - .HasForeignKey("OrganizationId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Organization"); - }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Send", b => { b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") @@ -1904,17 +1888,6 @@ namespace Bit.PostgresMigrations.Migrations b.Navigation("User"); }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ServiceAccount", b => - { - b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") - .WithMany() - .HasForeignKey("OrganizationId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Organization"); - }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoConfig", b => { b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") @@ -1958,24 +1931,66 @@ namespace Bit.PostgresMigrations.Migrations b.Navigation("User"); }); + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ApiKey", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccount", "ServiceAccount") + .WithMany() + .HasForeignKey("ServiceAccountId"); + + b.Navigation("ServiceAccount"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Project", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Secret", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccount", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + modelBuilder.Entity("ProjectSecret", b => { - b.HasOne("Bit.Infrastructure.EntityFramework.Models.Project", null) + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Project", null) .WithMany() .HasForeignKey("ProjectsId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("Bit.Infrastructure.EntityFramework.Models.Secret", null) + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Secret", null) .WithMany() .HasForeignKey("SecretsId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.GroupProjectAccessPolicy", b => + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.GroupProjectAccessPolicy", b => { - b.HasOne("Bit.Infrastructure.EntityFramework.Models.Project", "GrantedProject") + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Project", "GrantedProject") .WithMany("GroupAccessPolicies") .HasForeignKey("GrantedProjectId"); @@ -1988,10 +2003,10 @@ namespace Bit.PostgresMigrations.Migrations b.Navigation("Group"); }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.GroupServiceAccountAccessPolicy", b => + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.GroupServiceAccountAccessPolicy", b => { - b.HasOne("Bit.Infrastructure.EntityFramework.Models.ServiceAccount", "GrantedServiceAccount") - .WithMany() + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccount", "GrantedServiceAccount") + .WithMany("GroupAccessPolicies") .HasForeignKey("GrantedServiceAccountId"); b.HasOne("Bit.Infrastructure.EntityFramework.Models.Group", "Group") @@ -2003,13 +2018,13 @@ namespace Bit.PostgresMigrations.Migrations b.Navigation("Group"); }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ServiceAccountProjectAccessPolicy", b => + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccountProjectAccessPolicy", b => { - b.HasOne("Bit.Infrastructure.EntityFramework.Models.Project", "GrantedProject") + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Project", "GrantedProject") .WithMany("ServiceAccountAccessPolicies") .HasForeignKey("GrantedProjectId"); - b.HasOne("Bit.Infrastructure.EntityFramework.Models.ServiceAccount", "ServiceAccount") + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccount", "ServiceAccount") .WithMany() .HasForeignKey("ServiceAccountId"); @@ -2018,9 +2033,9 @@ namespace Bit.PostgresMigrations.Migrations b.Navigation("ServiceAccount"); }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.UserProjectAccessPolicy", b => + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.UserProjectAccessPolicy", b => { - b.HasOne("Bit.Infrastructure.EntityFramework.Models.Project", "GrantedProject") + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Project", "GrantedProject") .WithMany("UserAccessPolicies") .HasForeignKey("GrantedProjectId"); @@ -2033,10 +2048,10 @@ namespace Bit.PostgresMigrations.Migrations b.Navigation("OrganizationUser"); }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.UserServiceAccountAccessPolicy", b => + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.UserServiceAccountAccessPolicy", b => { - b.HasOne("Bit.Infrastructure.EntityFramework.Models.ServiceAccount", "GrantedServiceAccount") - .WithMany() + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccount", "GrantedServiceAccount") + .WithMany("UserAccessPolicies") .HasForeignKey("GrantedServiceAccountId"); b.HasOne("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", "OrganizationUser") @@ -2095,15 +2110,6 @@ namespace Bit.PostgresMigrations.Migrations b.Navigation("GroupUsers"); }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Project", b => - { - b.Navigation("GroupAccessPolicies"); - - b.Navigation("ServiceAccountAccessPolicies"); - - b.Navigation("UserAccessPolicies"); - }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.User", b => { b.Navigation("Ciphers"); @@ -2116,6 +2122,22 @@ namespace Bit.PostgresMigrations.Migrations b.Navigation("Transactions"); }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Project", b => + { + b.Navigation("GroupAccessPolicies"); + + b.Navigation("ServiceAccountAccessPolicies"); + + b.Navigation("UserAccessPolicies"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccount", b => + { + b.Navigation("GroupAccessPolicies"); + + b.Navigation("UserAccessPolicies"); + }); #pragma warning restore 612, 618 } } diff --git a/util/Setup/Configuration.cs b/util/Setup/Configuration.cs index 36f82ea4f5..bfe7b10d31 100644 --- a/util/Setup/Configuration.cs +++ b/util/Setup/Configuration.cs @@ -76,8 +76,9 @@ public class Configuration [Description("Nginx Header Content-Security-Policy parameter\n" + "WARNING: Reconfiguring this parameter may break features. By changing this parameter\n" + "you become responsible for maintaining this value.")] - public string NginxHeaderContentSecurityPolicy { get; set; } = "default-src 'self'; style-src 'self' " + - "'unsafe-inline'; img-src 'self' data: https://haveibeenpwned.com; " + + public string NginxHeaderContentSecurityPolicy { get; set; } = "default-src 'self'; " + + "script-src 'self' 'wasm-unsafe-eval'; style-src 'self' 'unsafe-inline'; " + + "img-src 'self' data: https://haveibeenpwned.com; " + "child-src 'self' https://*.duosecurity.com https://*.duofederal.com; " + "frame-src 'self' https://*.duosecurity.com https://*.duofederal.com; " + "connect-src 'self' wss://{0} https://api.pwnedpasswords.com " + diff --git a/util/SqliteMigrations/Migrations/20230201175211_SecretsManagerOrganizationUser.Designer.cs b/util/SqliteMigrations/Migrations/20230201175211_SecretsManagerOrganizationUser.Designer.cs new file mode 100644 index 0000000000..e66b3393d5 --- /dev/null +++ b/util/SqliteMigrations/Migrations/20230201175211_SecretsManagerOrganizationUser.Designer.cs @@ -0,0 +1,2118 @@ +// +using System; +using Bit.Infrastructure.EntityFramework.Repositories; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Bit.SqliteMigrations.Migrations +{ + [DbContext(typeof(DatabaseContext))] + [Migration("20230201175211_SecretsManagerOrganizationUser")] + partial class SecretsManagerOrganizationUser + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "6.0.12"); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.AuthRequest", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("AccessCode") + .HasMaxLength(25) + .HasColumnType("TEXT"); + + b.Property("Approved") + .HasColumnType("INTEGER"); + + b.Property("AuthenticationDate") + .HasColumnType("TEXT"); + + b.Property("CreationDate") + .HasColumnType("TEXT"); + + b.Property("Key") + .HasColumnType("TEXT"); + + b.Property("MasterPasswordHash") + .HasColumnType("TEXT"); + + b.Property("PublicKey") + .HasColumnType("TEXT"); + + b.Property("RequestDeviceIdentifier") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("RequestDeviceType") + .HasColumnType("INTEGER"); + + b.Property("RequestFingerprint") + .HasColumnType("TEXT"); + + b.Property("RequestIpAddress") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("ResponseDate") + .HasColumnType("TEXT"); + + b.Property("ResponseDeviceId") + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ResponseDeviceId"); + + b.HasIndex("UserId"); + + b.ToTable("AuthRequest", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Cipher", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("Attachments") + .HasColumnType("TEXT"); + + b.Property("CreationDate") + .HasColumnType("TEXT"); + + b.Property("Data") + .HasColumnType("TEXT"); + + b.Property("DeletedDate") + .HasColumnType("TEXT"); + + b.Property("Favorites") + .HasColumnType("TEXT"); + + b.Property("Folders") + .HasColumnType("TEXT"); + + b.Property("OrganizationId") + .HasColumnType("TEXT"); + + b.Property("Reprompt") + .HasColumnType("INTEGER"); + + b.Property("RevisionDate") + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("Cipher", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Collection", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("CreationDate") + .HasColumnType("TEXT"); + + b.Property("ExternalId") + .HasMaxLength(300) + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("OrganizationId") + .HasColumnType("TEXT"); + + b.Property("RevisionDate") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("Collection", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionCipher", b => + { + b.Property("CollectionId") + .HasColumnType("TEXT"); + + b.Property("CipherId") + .HasColumnType("TEXT"); + + b.HasKey("CollectionId", "CipherId"); + + b.HasIndex("CipherId"); + + b.ToTable("CollectionCipher", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionGroup", b => + { + b.Property("CollectionId") + .HasColumnType("TEXT"); + + b.Property("GroupId") + .HasColumnType("TEXT"); + + b.Property("HidePasswords") + .HasColumnType("INTEGER"); + + b.Property("ReadOnly") + .HasColumnType("INTEGER"); + + b.HasKey("CollectionId", "GroupId"); + + b.HasIndex("GroupId"); + + b.ToTable("CollectionGroups"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionUser", b => + { + b.Property("CollectionId") + .HasColumnType("TEXT"); + + b.Property("OrganizationUserId") + .HasColumnType("TEXT"); + + b.Property("HidePasswords") + .HasColumnType("INTEGER"); + + b.Property("ReadOnly") + .HasColumnType("INTEGER"); + + b.HasKey("CollectionId", "OrganizationUserId"); + + b.HasIndex("OrganizationUserId"); + + b.ToTable("CollectionUsers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Device", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("CreationDate") + .HasColumnType("TEXT"); + + b.Property("Identifier") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("PushToken") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("RevisionDate") + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("Device", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.EmergencyAccess", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("CreationDate") + .HasColumnType("TEXT"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("GranteeId") + .HasColumnType("TEXT"); + + b.Property("GrantorId") + .HasColumnType("TEXT"); + + b.Property("KeyEncrypted") + .HasColumnType("TEXT"); + + b.Property("LastNotificationDate") + .HasColumnType("TEXT"); + + b.Property("RecoveryInitiatedDate") + .HasColumnType("TEXT"); + + b.Property("RevisionDate") + .HasColumnType("TEXT"); + + b.Property("Status") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("WaitTimeDays") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GranteeId"); + + b.HasIndex("GrantorId"); + + b.ToTable("EmergencyAccess", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Event", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("ActingUserId") + .HasColumnType("TEXT"); + + b.Property("CipherId") + .HasColumnType("TEXT"); + + b.Property("CollectionId") + .HasColumnType("TEXT"); + + b.Property("Date") + .HasColumnType("TEXT"); + + b.Property("DeviceType") + .HasColumnType("INTEGER"); + + b.Property("GroupId") + .HasColumnType("TEXT"); + + b.Property("InstallationId") + .HasColumnType("TEXT"); + + b.Property("IpAddress") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("OrganizationId") + .HasColumnType("TEXT"); + + b.Property("OrganizationUserId") + .HasColumnType("TEXT"); + + b.Property("PolicyId") + .HasColumnType("TEXT"); + + b.Property("ProviderId") + .HasColumnType("TEXT"); + + b.Property("ProviderOrganizationId") + .HasColumnType("TEXT"); + + b.Property("ProviderUserId") + .HasColumnType("TEXT"); + + b.Property("SystemUser") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Event", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Folder", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("CreationDate") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("RevisionDate") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("Folder", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Grant", b => + { + b.Property("Key") + .HasMaxLength(200) + .HasColumnType("TEXT"); + + b.Property("ClientId") + .HasMaxLength(200) + .HasColumnType("TEXT"); + + b.Property("ConsumedDate") + .HasColumnType("TEXT"); + + b.Property("CreationDate") + .HasColumnType("TEXT"); + + b.Property("Data") + .HasColumnType("TEXT"); + + b.Property("Description") + .HasMaxLength(200) + .HasColumnType("TEXT"); + + b.Property("ExpirationDate") + .HasColumnType("TEXT"); + + b.Property("SessionId") + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.Property("SubjectId") + .HasMaxLength(200) + .HasColumnType("TEXT"); + + b.Property("Type") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.HasKey("Key"); + + b.ToTable("Grant", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Group", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("AccessAll") + .HasColumnType("INTEGER"); + + b.Property("CreationDate") + .HasColumnType("TEXT"); + + b.Property("ExternalId") + .HasMaxLength(300) + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.Property("OrganizationId") + .HasColumnType("TEXT"); + + b.Property("RevisionDate") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("Group", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.GroupUser", b => + { + b.Property("GroupId") + .HasColumnType("TEXT"); + + b.Property("OrganizationUserId") + .HasColumnType("TEXT"); + + b.HasKey("GroupId", "OrganizationUserId"); + + b.HasIndex("OrganizationUserId"); + + b.ToTable("GroupUser", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Installation", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("CreationDate") + .HasColumnType("TEXT"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("Enabled") + .HasColumnType("INTEGER"); + + b.Property("Key") + .HasMaxLength(150) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Installation", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Organization", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("BillingEmail") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("BusinessAddress1") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("BusinessAddress2") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("BusinessAddress3") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("BusinessCountry") + .HasMaxLength(2) + .HasColumnType("TEXT"); + + b.Property("BusinessName") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("BusinessTaxNumber") + .HasMaxLength(30) + .HasColumnType("TEXT"); + + b.Property("CreationDate") + .HasColumnType("TEXT"); + + b.Property("Enabled") + .HasColumnType("INTEGER"); + + b.Property("ExpirationDate") + .HasColumnType("TEXT"); + + b.Property("Gateway") + .HasColumnType("INTEGER"); + + b.Property("GatewayCustomerId") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("GatewaySubscriptionId") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("Identifier") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("LicenseKey") + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.Property("MaxAutoscaleSeats") + .HasColumnType("INTEGER"); + + b.Property("MaxCollections") + .HasColumnType("INTEGER"); + + b.Property("MaxStorageGb") + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("OwnersNotifiedOfAutoscaling") + .HasColumnType("TEXT"); + + b.Property("Plan") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("PlanType") + .HasColumnType("INTEGER"); + + b.Property("PrivateKey") + .HasColumnType("TEXT"); + + b.Property("PublicKey") + .HasColumnType("TEXT"); + + b.Property("ReferenceData") + .HasColumnType("TEXT"); + + b.Property("RevisionDate") + .HasColumnType("TEXT"); + + b.Property("Seats") + .HasColumnType("INTEGER"); + + b.Property("SelfHost") + .HasColumnType("INTEGER"); + + b.Property("Storage") + .HasColumnType("INTEGER"); + + b.Property("TwoFactorProviders") + .HasColumnType("TEXT"); + + b.Property("Use2fa") + .HasColumnType("INTEGER"); + + b.Property("UseApi") + .HasColumnType("INTEGER"); + + b.Property("UseCustomPermissions") + .HasColumnType("INTEGER"); + + b.Property("UseDirectory") + .HasColumnType("INTEGER"); + + b.Property("UseEvents") + .HasColumnType("INTEGER"); + + b.Property("UseGroups") + .HasColumnType("INTEGER"); + + b.Property("UseKeyConnector") + .HasColumnType("INTEGER"); + + b.Property("UsePolicies") + .HasColumnType("INTEGER"); + + b.Property("UseResetPassword") + .HasColumnType("INTEGER"); + + b.Property("UseScim") + .HasColumnType("INTEGER"); + + b.Property("UseSecretsManager") + .HasColumnType("INTEGER"); + + b.Property("UseSso") + .HasColumnType("INTEGER"); + + b.Property("UseTotp") + .HasColumnType("INTEGER"); + + b.Property("UsersGetPremium") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("Organization", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationApiKey", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("ApiKey") + .HasMaxLength(30) + .HasColumnType("TEXT"); + + b.Property("OrganizationId") + .HasColumnType("TEXT"); + + b.Property("RevisionDate") + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("OrganizationApiKey", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationConnection", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("Config") + .HasColumnType("TEXT"); + + b.Property("Enabled") + .HasColumnType("INTEGER"); + + b.Property("OrganizationId") + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("OrganizationConnection", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationSponsorship", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("FriendlyName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("LastSyncDate") + .HasColumnType("TEXT"); + + b.Property("OfferedToEmail") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("PlanSponsorshipType") + .HasColumnType("INTEGER"); + + b.Property("SponsoredOrganizationId") + .HasColumnType("TEXT"); + + b.Property("SponsoringOrganizationId") + .HasColumnType("TEXT"); + + b.Property("SponsoringOrganizationUserId") + .HasColumnType("TEXT"); + + b.Property("ToDelete") + .HasColumnType("INTEGER"); + + b.Property("ValidUntil") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("SponsoredOrganizationId"); + + b.HasIndex("SponsoringOrganizationId"); + + b.ToTable("OrganizationSponsorship", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("AccessAll") + .HasColumnType("INTEGER"); + + b.Property("AccessSecretsManager") + .HasColumnType("INTEGER"); + + b.Property("CreationDate") + .HasColumnType("TEXT"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("ExternalId") + .HasMaxLength(300) + .HasColumnType("TEXT"); + + b.Property("Key") + .HasColumnType("TEXT"); + + b.Property("OrganizationId") + .HasColumnType("TEXT"); + + b.Property("Permissions") + .HasColumnType("TEXT"); + + b.Property("ResetPasswordKey") + .HasColumnType("TEXT"); + + b.Property("RevisionDate") + .HasColumnType("TEXT"); + + b.Property("Status") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("OrganizationUser", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Policy", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("CreationDate") + .HasColumnType("TEXT"); + + b.Property("Data") + .HasColumnType("TEXT"); + + b.Property("Enabled") + .HasColumnType("INTEGER"); + + b.Property("OrganizationId") + .HasColumnType("TEXT"); + + b.Property("RevisionDate") + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("Policy", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Provider", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("BillingEmail") + .HasColumnType("TEXT"); + + b.Property("BillingPhone") + .HasColumnType("TEXT"); + + b.Property("BusinessAddress1") + .HasColumnType("TEXT"); + + b.Property("BusinessAddress2") + .HasColumnType("TEXT"); + + b.Property("BusinessAddress3") + .HasColumnType("TEXT"); + + b.Property("BusinessCountry") + .HasColumnType("TEXT"); + + b.Property("BusinessName") + .HasColumnType("TEXT"); + + b.Property("BusinessTaxNumber") + .HasColumnType("TEXT"); + + b.Property("CreationDate") + .HasColumnType("TEXT"); + + b.Property("Enabled") + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("RevisionDate") + .HasColumnType("TEXT"); + + b.Property("Status") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("UseEvents") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("Provider", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderOrganization", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("CreationDate") + .HasColumnType("TEXT"); + + b.Property("Key") + .HasColumnType("TEXT"); + + b.Property("OrganizationId") + .HasColumnType("TEXT"); + + b.Property("ProviderId") + .HasColumnType("TEXT"); + + b.Property("RevisionDate") + .HasColumnType("TEXT"); + + b.Property("Settings") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("ProviderId"); + + b.ToTable("ProviderOrganization", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderUser", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("CreationDate") + .HasColumnType("TEXT"); + + b.Property("Email") + .HasColumnType("TEXT"); + + b.Property("Key") + .HasColumnType("TEXT"); + + b.Property("Permissions") + .HasColumnType("TEXT"); + + b.Property("ProviderId") + .HasColumnType("TEXT"); + + b.Property("RevisionDate") + .HasColumnType("TEXT"); + + b.Property("Status") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ProviderId"); + + b.HasIndex("UserId"); + + b.ToTable("ProviderUser", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Send", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("AccessCount") + .HasColumnType("INTEGER"); + + b.Property("CreationDate") + .HasColumnType("TEXT"); + + b.Property("Data") + .HasColumnType("TEXT"); + + b.Property("DeletionDate") + .HasColumnType("TEXT"); + + b.Property("Disabled") + .HasColumnType("INTEGER"); + + b.Property("ExpirationDate") + .HasColumnType("TEXT"); + + b.Property("HideEmail") + .HasColumnType("INTEGER"); + + b.Property("Key") + .HasColumnType("TEXT"); + + b.Property("MaxAccessCount") + .HasColumnType("INTEGER"); + + b.Property("OrganizationId") + .HasColumnType("TEXT"); + + b.Property("Password") + .HasMaxLength(300) + .HasColumnType("TEXT"); + + b.Property("RevisionDate") + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("Send", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CreationDate") + .HasColumnType("TEXT"); + + b.Property("Data") + .HasColumnType("TEXT"); + + b.Property("Enabled") + .HasColumnType("INTEGER"); + + b.Property("OrganizationId") + .HasColumnType("TEXT"); + + b.Property("RevisionDate") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("SsoConfig", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CreationDate") + .HasColumnType("TEXT"); + + b.Property("ExternalId") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("OrganizationId") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("SsoUser", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.TaxRate", b => + { + b.Property("Id") + .HasMaxLength(40) + .HasColumnType("TEXT"); + + b.Property("Active") + .HasColumnType("INTEGER"); + + b.Property("Country") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("PostalCode") + .HasMaxLength(10) + .HasColumnType("TEXT"); + + b.Property("Rate") + .HasColumnType("TEXT"); + + b.Property("State") + .HasMaxLength(2) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("TaxRate", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Transaction", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("Amount") + .HasColumnType("TEXT"); + + b.Property("CreationDate") + .HasColumnType("TEXT"); + + b.Property("Details") + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.Property("Gateway") + .HasColumnType("INTEGER"); + + b.Property("GatewayId") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("OrganizationId") + .HasColumnType("TEXT"); + + b.Property("PaymentMethodType") + .HasColumnType("INTEGER"); + + b.Property("Refunded") + .HasColumnType("INTEGER"); + + b.Property("RefundedAmount") + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("Transaction", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.User", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("AccountRevisionDate") + .HasColumnType("TEXT"); + + b.Property("ApiKey") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("TEXT"); + + b.Property("AvatarColor") + .HasMaxLength(7) + .HasColumnType("TEXT"); + + b.Property("CreationDate") + .HasColumnType("TEXT"); + + b.Property("Culture") + .HasMaxLength(10) + .HasColumnType("TEXT"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("EmailVerified") + .HasColumnType("INTEGER"); + + b.Property("EquivalentDomains") + .HasColumnType("TEXT"); + + b.Property("ExcludedGlobalEquivalentDomains") + .HasColumnType("TEXT"); + + b.Property("FailedLoginCount") + .HasColumnType("INTEGER"); + + b.Property("ForcePasswordReset") + .HasColumnType("INTEGER"); + + b.Property("Gateway") + .HasColumnType("INTEGER"); + + b.Property("GatewayCustomerId") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("GatewaySubscriptionId") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("Kdf") + .HasColumnType("INTEGER"); + + b.Property("KdfIterations") + .HasColumnType("INTEGER"); + + b.Property("KdfMemory") + .HasColumnType("INTEGER"); + + b.Property("KdfParallelism") + .HasColumnType("INTEGER"); + + b.Property("Key") + .HasColumnType("TEXT"); + + b.Property("LastFailedLoginDate") + .HasColumnType("TEXT"); + + b.Property("LicenseKey") + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.Property("MasterPassword") + .HasMaxLength(300) + .HasColumnType("TEXT"); + + b.Property("MasterPasswordHint") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("MaxStorageGb") + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("Premium") + .HasColumnType("INTEGER"); + + b.Property("PremiumExpirationDate") + .HasColumnType("TEXT"); + + b.Property("PrivateKey") + .HasColumnType("TEXT"); + + b.Property("PublicKey") + .HasColumnType("TEXT"); + + b.Property("ReferenceData") + .HasColumnType("TEXT"); + + b.Property("RenewalReminderDate") + .HasColumnType("TEXT"); + + b.Property("RevisionDate") + .HasColumnType("TEXT"); + + b.Property("SecurityStamp") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("Storage") + .HasColumnType("INTEGER"); + + b.Property("TwoFactorProviders") + .HasColumnType("TEXT"); + + b.Property("TwoFactorRecoveryCode") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("UnknownDeviceVerificationEnabled") + .HasColumnType("INTEGER"); + + b.Property("UsesKeyConnector") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("User", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.AccessPolicy", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("CreationDate") + .HasColumnType("TEXT"); + + b.Property("Discriminator") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Read") + .HasColumnType("INTEGER"); + + b.Property("RevisionDate") + .HasColumnType("TEXT"); + + b.Property("Write") + .HasColumnType("INTEGER"); + + b.HasKey("Id") + .HasAnnotation("SqlServer:Clustered", true); + + b.ToTable("AccessPolicy", (string)null); + + b.HasDiscriminator("Discriminator").HasValue("AccessPolicy"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ApiKey", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("ClientSecret") + .HasMaxLength(30) + .HasColumnType("TEXT"); + + b.Property("CreationDate") + .HasColumnType("TEXT"); + + b.Property("EncryptedPayload") + .HasMaxLength(4000) + .HasColumnType("TEXT"); + + b.Property("ExpireAt") + .HasColumnType("TEXT"); + + b.Property("Key") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(200) + .HasColumnType("TEXT"); + + b.Property("RevisionDate") + .HasColumnType("TEXT"); + + b.Property("Scope") + .HasMaxLength(4000) + .HasColumnType("TEXT"); + + b.Property("ServiceAccountId") + .HasColumnType("TEXT"); + + b.HasKey("Id") + .HasAnnotation("SqlServer:Clustered", true); + + b.HasIndex("ServiceAccountId") + .HasAnnotation("SqlServer:Clustered", false); + + b.ToTable("ApiKey", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Project", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("CreationDate") + .HasColumnType("TEXT"); + + b.Property("DeletedDate") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("OrganizationId") + .HasColumnType("TEXT"); + + b.Property("RevisionDate") + .HasColumnType("TEXT"); + + b.HasKey("Id") + .HasAnnotation("SqlServer:Clustered", true); + + b.HasIndex("DeletedDate") + .HasAnnotation("SqlServer:Clustered", false); + + b.HasIndex("OrganizationId") + .HasAnnotation("SqlServer:Clustered", false); + + b.ToTable("Project", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Secret", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("CreationDate") + .HasColumnType("TEXT"); + + b.Property("DeletedDate") + .HasColumnType("TEXT"); + + b.Property("Key") + .HasColumnType("TEXT"); + + b.Property("Note") + .HasColumnType("TEXT"); + + b.Property("OrganizationId") + .HasColumnType("TEXT"); + + b.Property("RevisionDate") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("Id") + .HasAnnotation("SqlServer:Clustered", true); + + b.HasIndex("DeletedDate") + .HasAnnotation("SqlServer:Clustered", false); + + b.HasIndex("OrganizationId") + .HasAnnotation("SqlServer:Clustered", false); + + b.ToTable("Secret", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccount", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("CreationDate") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("OrganizationId") + .HasColumnType("TEXT"); + + b.Property("RevisionDate") + .HasColumnType("TEXT"); + + b.HasKey("Id") + .HasAnnotation("SqlServer:Clustered", true); + + b.HasIndex("OrganizationId") + .HasAnnotation("SqlServer:Clustered", false); + + b.ToTable("ServiceAccount", (string)null); + }); + + modelBuilder.Entity("ProjectSecret", b => + { + b.Property("ProjectsId") + .HasColumnType("TEXT"); + + b.Property("SecretsId") + .HasColumnType("TEXT"); + + b.HasKey("ProjectsId", "SecretsId"); + + b.HasIndex("SecretsId"); + + b.ToTable("ProjectSecret"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.GroupProjectAccessPolicy", b => + { + b.HasBaseType("Bit.Infrastructure.EntityFramework.SecretsManager.Models.AccessPolicy"); + + b.Property("GrantedProjectId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("TEXT") + .HasColumnName("GrantedProjectId"); + + b.Property("GroupId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("TEXT") + .HasColumnName("GroupId"); + + b.HasIndex("GrantedProjectId"); + + b.HasIndex("GroupId"); + + b.HasDiscriminator().HasValue("group_project"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.GroupServiceAccountAccessPolicy", b => + { + b.HasBaseType("Bit.Infrastructure.EntityFramework.SecretsManager.Models.AccessPolicy"); + + b.Property("GrantedServiceAccountId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("TEXT") + .HasColumnName("GrantedServiceAccountId"); + + b.Property("GroupId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("TEXT") + .HasColumnName("GroupId"); + + b.HasIndex("GrantedServiceAccountId"); + + b.HasIndex("GroupId"); + + b.HasDiscriminator().HasValue("group_service_account"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccountProjectAccessPolicy", b => + { + b.HasBaseType("Bit.Infrastructure.EntityFramework.SecretsManager.Models.AccessPolicy"); + + b.Property("GrantedProjectId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("TEXT") + .HasColumnName("GrantedProjectId"); + + b.Property("ServiceAccountId") + .HasColumnType("TEXT") + .HasColumnName("ServiceAccountId"); + + b.HasIndex("GrantedProjectId"); + + b.HasIndex("ServiceAccountId"); + + b.HasDiscriminator().HasValue("service_account_project"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.UserProjectAccessPolicy", b => + { + b.HasBaseType("Bit.Infrastructure.EntityFramework.SecretsManager.Models.AccessPolicy"); + + b.Property("GrantedProjectId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("TEXT") + .HasColumnName("GrantedProjectId"); + + b.Property("OrganizationUserId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("TEXT") + .HasColumnName("OrganizationUserId"); + + b.HasIndex("GrantedProjectId"); + + b.HasIndex("OrganizationUserId"); + + b.HasDiscriminator().HasValue("user_project"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.UserServiceAccountAccessPolicy", b => + { + b.HasBaseType("Bit.Infrastructure.EntityFramework.SecretsManager.Models.AccessPolicy"); + + b.Property("GrantedServiceAccountId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("TEXT") + .HasColumnName("GrantedServiceAccountId"); + + b.Property("OrganizationUserId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("TEXT") + .HasColumnName("OrganizationUserId"); + + b.HasIndex("GrantedServiceAccountId"); + + b.HasIndex("OrganizationUserId"); + + b.HasDiscriminator().HasValue("user_service_account"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.AuthRequest", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Device", "ResponseDevice") + .WithMany() + .HasForeignKey("ResponseDeviceId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ResponseDevice"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Cipher", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Ciphers") + .HasForeignKey("OrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("Ciphers") + .HasForeignKey("UserId"); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Collection", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionCipher", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Cipher", "Cipher") + .WithMany("CollectionCiphers") + .HasForeignKey("CipherId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Collection", "Collection") + .WithMany("CollectionCiphers") + .HasForeignKey("CollectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Cipher"); + + b.Navigation("Collection"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionGroup", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Collection", "Collection") + .WithMany("CollectionGroups") + .HasForeignKey("CollectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Group", "Group") + .WithMany() + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Collection"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Collection", "Collection") + .WithMany("CollectionUsers") + .HasForeignKey("CollectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", "OrganizationUser") + .WithMany("CollectionUsers") + .HasForeignKey("OrganizationUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Collection"); + + b.Navigation("OrganizationUser"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Device", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.EmergencyAccess", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "Grantee") + .WithMany() + .HasForeignKey("GranteeId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "Grantor") + .WithMany() + .HasForeignKey("GrantorId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Grantee"); + + b.Navigation("Grantor"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Folder", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("Folders") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Group", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Groups") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.GroupUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Group", "Group") + .WithMany("GroupUsers") + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", "OrganizationUser") + .WithMany("GroupUsers") + .HasForeignKey("OrganizationUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Group"); + + b.Navigation("OrganizationUser"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationApiKey", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("ApiKeys") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationConnection", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Connections") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationSponsorship", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "SponsoredOrganization") + .WithMany() + .HasForeignKey("SponsoredOrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "SponsoringOrganization") + .WithMany() + .HasForeignKey("SponsoringOrganizationId"); + + b.Navigation("SponsoredOrganization"); + + b.Navigation("SponsoringOrganization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("OrganizationUsers") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("OrganizationUsers") + .HasForeignKey("UserId"); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Policy", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Policies") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderOrganization", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Provider", "Provider") + .WithMany() + .HasForeignKey("ProviderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + + b.Navigation("Provider"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Provider", "Provider") + .WithMany() + .HasForeignKey("ProviderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany() + .HasForeignKey("UserId"); + + b.Navigation("Provider"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Send", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany() + .HasForeignKey("UserId"); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoConfig", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("SsoConfigs") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("SsoUsers") + .HasForeignKey("OrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("SsoUsers") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Transaction", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Transactions") + .HasForeignKey("OrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("Transactions") + .HasForeignKey("UserId"); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ApiKey", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccount", "ServiceAccount") + .WithMany() + .HasForeignKey("ServiceAccountId"); + + b.Navigation("ServiceAccount"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Project", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Secret", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccount", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("ProjectSecret", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Project", null) + .WithMany() + .HasForeignKey("ProjectsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Secret", null) + .WithMany() + .HasForeignKey("SecretsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.GroupProjectAccessPolicy", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Project", "GrantedProject") + .WithMany("GroupAccessPolicies") + .HasForeignKey("GrantedProjectId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Group", "Group") + .WithMany() + .HasForeignKey("GroupId"); + + b.Navigation("GrantedProject"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.GroupServiceAccountAccessPolicy", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccount", "GrantedServiceAccount") + .WithMany("GroupAccessPolicies") + .HasForeignKey("GrantedServiceAccountId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Group", "Group") + .WithMany() + .HasForeignKey("GroupId"); + + b.Navigation("GrantedServiceAccount"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccountProjectAccessPolicy", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Project", "GrantedProject") + .WithMany("ServiceAccountAccessPolicies") + .HasForeignKey("GrantedProjectId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccount", "ServiceAccount") + .WithMany() + .HasForeignKey("ServiceAccountId"); + + b.Navigation("GrantedProject"); + + b.Navigation("ServiceAccount"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.UserProjectAccessPolicy", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Project", "GrantedProject") + .WithMany("UserAccessPolicies") + .HasForeignKey("GrantedProjectId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", "OrganizationUser") + .WithMany() + .HasForeignKey("OrganizationUserId"); + + b.Navigation("GrantedProject"); + + b.Navigation("OrganizationUser"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.UserServiceAccountAccessPolicy", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccount", "GrantedServiceAccount") + .WithMany("UserAccessPolicies") + .HasForeignKey("GrantedServiceAccountId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", "OrganizationUser") + .WithMany() + .HasForeignKey("OrganizationUserId"); + + b.Navigation("GrantedServiceAccount"); + + b.Navigation("OrganizationUser"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Cipher", b => + { + b.Navigation("CollectionCiphers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Collection", b => + { + b.Navigation("CollectionCiphers"); + + b.Navigation("CollectionGroups"); + + b.Navigation("CollectionUsers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Group", b => + { + b.Navigation("GroupUsers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Organization", b => + { + b.Navigation("ApiKeys"); + + b.Navigation("Ciphers"); + + b.Navigation("Connections"); + + b.Navigation("Groups"); + + b.Navigation("OrganizationUsers"); + + b.Navigation("Policies"); + + b.Navigation("SsoConfigs"); + + b.Navigation("SsoUsers"); + + b.Navigation("Transactions"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", b => + { + b.Navigation("CollectionUsers"); + + b.Navigation("GroupUsers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.User", b => + { + b.Navigation("Ciphers"); + + b.Navigation("Folders"); + + b.Navigation("OrganizationUsers"); + + b.Navigation("SsoUsers"); + + b.Navigation("Transactions"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Project", b => + { + b.Navigation("GroupAccessPolicies"); + + b.Navigation("ServiceAccountAccessPolicies"); + + b.Navigation("UserAccessPolicies"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccount", b => + { + b.Navigation("GroupAccessPolicies"); + + b.Navigation("UserAccessPolicies"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/util/SqliteMigrations/Migrations/20230201175211_SecretsManagerOrganizationUser.cs b/util/SqliteMigrations/Migrations/20230201175211_SecretsManagerOrganizationUser.cs new file mode 100644 index 0000000000..fda26a8f9e --- /dev/null +++ b/util/SqliteMigrations/Migrations/20230201175211_SecretsManagerOrganizationUser.cs @@ -0,0 +1,25 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Bit.SqliteMigrations.Migrations; + +public partial class SecretsManagerOrganizationUser : Migration +{ + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "AccessSecretsManager", + table: "OrganizationUser", + type: "INTEGER", + nullable: false, + defaultValue: false); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "AccessSecretsManager", + table: "OrganizationUser"); + } +} diff --git a/util/SqliteMigrations/Migrations/20230201192604_LastUserDates.Designer.cs b/util/SqliteMigrations/Migrations/20230201192604_LastUserDates.Designer.cs new file mode 100644 index 0000000000..8992b4f0a2 --- /dev/null +++ b/util/SqliteMigrations/Migrations/20230201192604_LastUserDates.Designer.cs @@ -0,0 +1,2130 @@ +// +using System; +using Bit.Infrastructure.EntityFramework.Repositories; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Bit.SqliteMigrations.Migrations +{ + [DbContext(typeof(DatabaseContext))] + [Migration("20230201192604_LastUserDates")] + partial class LastUserDates + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "6.0.12"); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.AuthRequest", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("AccessCode") + .HasMaxLength(25) + .HasColumnType("TEXT"); + + b.Property("Approved") + .HasColumnType("INTEGER"); + + b.Property("AuthenticationDate") + .HasColumnType("TEXT"); + + b.Property("CreationDate") + .HasColumnType("TEXT"); + + b.Property("Key") + .HasColumnType("TEXT"); + + b.Property("MasterPasswordHash") + .HasColumnType("TEXT"); + + b.Property("PublicKey") + .HasColumnType("TEXT"); + + b.Property("RequestDeviceIdentifier") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("RequestDeviceType") + .HasColumnType("INTEGER"); + + b.Property("RequestFingerprint") + .HasColumnType("TEXT"); + + b.Property("RequestIpAddress") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("ResponseDate") + .HasColumnType("TEXT"); + + b.Property("ResponseDeviceId") + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ResponseDeviceId"); + + b.HasIndex("UserId"); + + b.ToTable("AuthRequest", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Cipher", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("Attachments") + .HasColumnType("TEXT"); + + b.Property("CreationDate") + .HasColumnType("TEXT"); + + b.Property("Data") + .HasColumnType("TEXT"); + + b.Property("DeletedDate") + .HasColumnType("TEXT"); + + b.Property("Favorites") + .HasColumnType("TEXT"); + + b.Property("Folders") + .HasColumnType("TEXT"); + + b.Property("OrganizationId") + .HasColumnType("TEXT"); + + b.Property("Reprompt") + .HasColumnType("INTEGER"); + + b.Property("RevisionDate") + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("Cipher", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Collection", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("CreationDate") + .HasColumnType("TEXT"); + + b.Property("ExternalId") + .HasMaxLength(300) + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("OrganizationId") + .HasColumnType("TEXT"); + + b.Property("RevisionDate") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("Collection", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionCipher", b => + { + b.Property("CollectionId") + .HasColumnType("TEXT"); + + b.Property("CipherId") + .HasColumnType("TEXT"); + + b.HasKey("CollectionId", "CipherId"); + + b.HasIndex("CipherId"); + + b.ToTable("CollectionCipher", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionGroup", b => + { + b.Property("CollectionId") + .HasColumnType("TEXT"); + + b.Property("GroupId") + .HasColumnType("TEXT"); + + b.Property("HidePasswords") + .HasColumnType("INTEGER"); + + b.Property("ReadOnly") + .HasColumnType("INTEGER"); + + b.HasKey("CollectionId", "GroupId"); + + b.HasIndex("GroupId"); + + b.ToTable("CollectionGroups"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionUser", b => + { + b.Property("CollectionId") + .HasColumnType("TEXT"); + + b.Property("OrganizationUserId") + .HasColumnType("TEXT"); + + b.Property("HidePasswords") + .HasColumnType("INTEGER"); + + b.Property("ReadOnly") + .HasColumnType("INTEGER"); + + b.HasKey("CollectionId", "OrganizationUserId"); + + b.HasIndex("OrganizationUserId"); + + b.ToTable("CollectionUsers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Device", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("CreationDate") + .HasColumnType("TEXT"); + + b.Property("Identifier") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("PushToken") + .HasMaxLength(255) + .HasColumnType("TEXT"); + + b.Property("RevisionDate") + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("Device", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.EmergencyAccess", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("CreationDate") + .HasColumnType("TEXT"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("GranteeId") + .HasColumnType("TEXT"); + + b.Property("GrantorId") + .HasColumnType("TEXT"); + + b.Property("KeyEncrypted") + .HasColumnType("TEXT"); + + b.Property("LastNotificationDate") + .HasColumnType("TEXT"); + + b.Property("RecoveryInitiatedDate") + .HasColumnType("TEXT"); + + b.Property("RevisionDate") + .HasColumnType("TEXT"); + + b.Property("Status") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("WaitTimeDays") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("GranteeId"); + + b.HasIndex("GrantorId"); + + b.ToTable("EmergencyAccess", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Event", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("ActingUserId") + .HasColumnType("TEXT"); + + b.Property("CipherId") + .HasColumnType("TEXT"); + + b.Property("CollectionId") + .HasColumnType("TEXT"); + + b.Property("Date") + .HasColumnType("TEXT"); + + b.Property("DeviceType") + .HasColumnType("INTEGER"); + + b.Property("GroupId") + .HasColumnType("TEXT"); + + b.Property("InstallationId") + .HasColumnType("TEXT"); + + b.Property("IpAddress") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("OrganizationId") + .HasColumnType("TEXT"); + + b.Property("OrganizationUserId") + .HasColumnType("TEXT"); + + b.Property("PolicyId") + .HasColumnType("TEXT"); + + b.Property("ProviderId") + .HasColumnType("TEXT"); + + b.Property("ProviderOrganizationId") + .HasColumnType("TEXT"); + + b.Property("ProviderUserId") + .HasColumnType("TEXT"); + + b.Property("SystemUser") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Event", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Folder", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("CreationDate") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("RevisionDate") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("Folder", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Grant", b => + { + b.Property("Key") + .HasMaxLength(200) + .HasColumnType("TEXT"); + + b.Property("ClientId") + .HasMaxLength(200) + .HasColumnType("TEXT"); + + b.Property("ConsumedDate") + .HasColumnType("TEXT"); + + b.Property("CreationDate") + .HasColumnType("TEXT"); + + b.Property("Data") + .HasColumnType("TEXT"); + + b.Property("Description") + .HasMaxLength(200) + .HasColumnType("TEXT"); + + b.Property("ExpirationDate") + .HasColumnType("TEXT"); + + b.Property("SessionId") + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.Property("SubjectId") + .HasMaxLength(200) + .HasColumnType("TEXT"); + + b.Property("Type") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.HasKey("Key"); + + b.ToTable("Grant", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Group", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("AccessAll") + .HasColumnType("INTEGER"); + + b.Property("CreationDate") + .HasColumnType("TEXT"); + + b.Property("ExternalId") + .HasMaxLength(300) + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.Property("OrganizationId") + .HasColumnType("TEXT"); + + b.Property("RevisionDate") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("Group", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.GroupUser", b => + { + b.Property("GroupId") + .HasColumnType("TEXT"); + + b.Property("OrganizationUserId") + .HasColumnType("TEXT"); + + b.HasKey("GroupId", "OrganizationUserId"); + + b.HasIndex("OrganizationUserId"); + + b.ToTable("GroupUser", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Installation", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("CreationDate") + .HasColumnType("TEXT"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("Enabled") + .HasColumnType("INTEGER"); + + b.Property("Key") + .HasMaxLength(150) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Installation", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Organization", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("BillingEmail") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("BusinessAddress1") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("BusinessAddress2") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("BusinessAddress3") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("BusinessCountry") + .HasMaxLength(2) + .HasColumnType("TEXT"); + + b.Property("BusinessName") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("BusinessTaxNumber") + .HasMaxLength(30) + .HasColumnType("TEXT"); + + b.Property("CreationDate") + .HasColumnType("TEXT"); + + b.Property("Enabled") + .HasColumnType("INTEGER"); + + b.Property("ExpirationDate") + .HasColumnType("TEXT"); + + b.Property("Gateway") + .HasColumnType("INTEGER"); + + b.Property("GatewayCustomerId") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("GatewaySubscriptionId") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("Identifier") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("LicenseKey") + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.Property("MaxAutoscaleSeats") + .HasColumnType("INTEGER"); + + b.Property("MaxCollections") + .HasColumnType("INTEGER"); + + b.Property("MaxStorageGb") + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("OwnersNotifiedOfAutoscaling") + .HasColumnType("TEXT"); + + b.Property("Plan") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("PlanType") + .HasColumnType("INTEGER"); + + b.Property("PrivateKey") + .HasColumnType("TEXT"); + + b.Property("PublicKey") + .HasColumnType("TEXT"); + + b.Property("ReferenceData") + .HasColumnType("TEXT"); + + b.Property("RevisionDate") + .HasColumnType("TEXT"); + + b.Property("Seats") + .HasColumnType("INTEGER"); + + b.Property("SelfHost") + .HasColumnType("INTEGER"); + + b.Property("Storage") + .HasColumnType("INTEGER"); + + b.Property("TwoFactorProviders") + .HasColumnType("TEXT"); + + b.Property("Use2fa") + .HasColumnType("INTEGER"); + + b.Property("UseApi") + .HasColumnType("INTEGER"); + + b.Property("UseCustomPermissions") + .HasColumnType("INTEGER"); + + b.Property("UseDirectory") + .HasColumnType("INTEGER"); + + b.Property("UseEvents") + .HasColumnType("INTEGER"); + + b.Property("UseGroups") + .HasColumnType("INTEGER"); + + b.Property("UseKeyConnector") + .HasColumnType("INTEGER"); + + b.Property("UsePolicies") + .HasColumnType("INTEGER"); + + b.Property("UseResetPassword") + .HasColumnType("INTEGER"); + + b.Property("UseScim") + .HasColumnType("INTEGER"); + + b.Property("UseSecretsManager") + .HasColumnType("INTEGER"); + + b.Property("UseSso") + .HasColumnType("INTEGER"); + + b.Property("UseTotp") + .HasColumnType("INTEGER"); + + b.Property("UsersGetPremium") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("Organization", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationApiKey", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("ApiKey") + .HasMaxLength(30) + .HasColumnType("TEXT"); + + b.Property("OrganizationId") + .HasColumnType("TEXT"); + + b.Property("RevisionDate") + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("OrganizationApiKey", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationConnection", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("Config") + .HasColumnType("TEXT"); + + b.Property("Enabled") + .HasColumnType("INTEGER"); + + b.Property("OrganizationId") + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("OrganizationConnection", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationSponsorship", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("FriendlyName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("LastSyncDate") + .HasColumnType("TEXT"); + + b.Property("OfferedToEmail") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("PlanSponsorshipType") + .HasColumnType("INTEGER"); + + b.Property("SponsoredOrganizationId") + .HasColumnType("TEXT"); + + b.Property("SponsoringOrganizationId") + .HasColumnType("TEXT"); + + b.Property("SponsoringOrganizationUserId") + .HasColumnType("TEXT"); + + b.Property("ToDelete") + .HasColumnType("INTEGER"); + + b.Property("ValidUntil") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("SponsoredOrganizationId"); + + b.HasIndex("SponsoringOrganizationId"); + + b.ToTable("OrganizationSponsorship", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("AccessAll") + .HasColumnType("INTEGER"); + + b.Property("AccessSecretsManager") + .HasColumnType("INTEGER"); + + b.Property("CreationDate") + .HasColumnType("TEXT"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("ExternalId") + .HasMaxLength(300) + .HasColumnType("TEXT"); + + b.Property("Key") + .HasColumnType("TEXT"); + + b.Property("OrganizationId") + .HasColumnType("TEXT"); + + b.Property("Permissions") + .HasColumnType("TEXT"); + + b.Property("ResetPasswordKey") + .HasColumnType("TEXT"); + + b.Property("RevisionDate") + .HasColumnType("TEXT"); + + b.Property("Status") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("OrganizationUser", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Policy", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("CreationDate") + .HasColumnType("TEXT"); + + b.Property("Data") + .HasColumnType("TEXT"); + + b.Property("Enabled") + .HasColumnType("INTEGER"); + + b.Property("OrganizationId") + .HasColumnType("TEXT"); + + b.Property("RevisionDate") + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("Policy", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Provider", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("BillingEmail") + .HasColumnType("TEXT"); + + b.Property("BillingPhone") + .HasColumnType("TEXT"); + + b.Property("BusinessAddress1") + .HasColumnType("TEXT"); + + b.Property("BusinessAddress2") + .HasColumnType("TEXT"); + + b.Property("BusinessAddress3") + .HasColumnType("TEXT"); + + b.Property("BusinessCountry") + .HasColumnType("TEXT"); + + b.Property("BusinessName") + .HasColumnType("TEXT"); + + b.Property("BusinessTaxNumber") + .HasColumnType("TEXT"); + + b.Property("CreationDate") + .HasColumnType("TEXT"); + + b.Property("Enabled") + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("RevisionDate") + .HasColumnType("TEXT"); + + b.Property("Status") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("UseEvents") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("Provider", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderOrganization", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("CreationDate") + .HasColumnType("TEXT"); + + b.Property("Key") + .HasColumnType("TEXT"); + + b.Property("OrganizationId") + .HasColumnType("TEXT"); + + b.Property("ProviderId") + .HasColumnType("TEXT"); + + b.Property("RevisionDate") + .HasColumnType("TEXT"); + + b.Property("Settings") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("ProviderId"); + + b.ToTable("ProviderOrganization", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderUser", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("CreationDate") + .HasColumnType("TEXT"); + + b.Property("Email") + .HasColumnType("TEXT"); + + b.Property("Key") + .HasColumnType("TEXT"); + + b.Property("Permissions") + .HasColumnType("TEXT"); + + b.Property("ProviderId") + .HasColumnType("TEXT"); + + b.Property("RevisionDate") + .HasColumnType("TEXT"); + + b.Property("Status") + .HasColumnType("INTEGER"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("ProviderId"); + + b.HasIndex("UserId"); + + b.ToTable("ProviderUser", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Send", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("AccessCount") + .HasColumnType("INTEGER"); + + b.Property("CreationDate") + .HasColumnType("TEXT"); + + b.Property("Data") + .HasColumnType("TEXT"); + + b.Property("DeletionDate") + .HasColumnType("TEXT"); + + b.Property("Disabled") + .HasColumnType("INTEGER"); + + b.Property("ExpirationDate") + .HasColumnType("TEXT"); + + b.Property("HideEmail") + .HasColumnType("INTEGER"); + + b.Property("Key") + .HasColumnType("TEXT"); + + b.Property("MaxAccessCount") + .HasColumnType("INTEGER"); + + b.Property("OrganizationId") + .HasColumnType("TEXT"); + + b.Property("Password") + .HasMaxLength(300) + .HasColumnType("TEXT"); + + b.Property("RevisionDate") + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("Send", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CreationDate") + .HasColumnType("TEXT"); + + b.Property("Data") + .HasColumnType("TEXT"); + + b.Property("Enabled") + .HasColumnType("INTEGER"); + + b.Property("OrganizationId") + .HasColumnType("TEXT"); + + b.Property("RevisionDate") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.ToTable("SsoConfig", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoUser", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CreationDate") + .HasColumnType("TEXT"); + + b.Property("ExternalId") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("OrganizationId") + .HasColumnType("TEXT"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("SsoUser", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.TaxRate", b => + { + b.Property("Id") + .HasMaxLength(40) + .HasColumnType("TEXT"); + + b.Property("Active") + .HasColumnType("INTEGER"); + + b.Property("Country") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("PostalCode") + .HasMaxLength(10) + .HasColumnType("TEXT"); + + b.Property("Rate") + .HasColumnType("TEXT"); + + b.Property("State") + .HasMaxLength(2) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("TaxRate", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Transaction", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("Amount") + .HasColumnType("TEXT"); + + b.Property("CreationDate") + .HasColumnType("TEXT"); + + b.Property("Details") + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.Property("Gateway") + .HasColumnType("INTEGER"); + + b.Property("GatewayId") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("OrganizationId") + .HasColumnType("TEXT"); + + b.Property("PaymentMethodType") + .HasColumnType("INTEGER"); + + b.Property("Refunded") + .HasColumnType("INTEGER"); + + b.Property("RefundedAmount") + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("UserId") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("OrganizationId"); + + b.HasIndex("UserId"); + + b.ToTable("Transaction", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.User", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("AccountRevisionDate") + .HasColumnType("TEXT"); + + b.Property("ApiKey") + .IsRequired() + .HasMaxLength(30) + .HasColumnType("TEXT"); + + b.Property("AvatarColor") + .HasMaxLength(7) + .HasColumnType("TEXT"); + + b.Property("CreationDate") + .HasColumnType("TEXT"); + + b.Property("Culture") + .HasMaxLength(10) + .HasColumnType("TEXT"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("EmailVerified") + .HasColumnType("INTEGER"); + + b.Property("EquivalentDomains") + .HasColumnType("TEXT"); + + b.Property("ExcludedGlobalEquivalentDomains") + .HasColumnType("TEXT"); + + b.Property("FailedLoginCount") + .HasColumnType("INTEGER"); + + b.Property("ForcePasswordReset") + .HasColumnType("INTEGER"); + + b.Property("Gateway") + .HasColumnType("INTEGER"); + + b.Property("GatewayCustomerId") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("GatewaySubscriptionId") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("Kdf") + .HasColumnType("INTEGER"); + + b.Property("KdfIterations") + .HasColumnType("INTEGER"); + + b.Property("KdfMemory") + .HasColumnType("INTEGER"); + + b.Property("KdfParallelism") + .HasColumnType("INTEGER"); + + b.Property("Key") + .HasColumnType("TEXT"); + + b.Property("LastEmailChangeDate") + .HasColumnType("TEXT"); + + b.Property("LastFailedLoginDate") + .HasColumnType("TEXT"); + + b.Property("LastKdfChangeDate") + .HasColumnType("TEXT"); + + b.Property("LastKeyRotationDate") + .HasColumnType("TEXT"); + + b.Property("LastPasswordChangeDate") + .HasColumnType("TEXT"); + + b.Property("LicenseKey") + .HasMaxLength(100) + .HasColumnType("TEXT"); + + b.Property("MasterPassword") + .HasMaxLength(300) + .HasColumnType("TEXT"); + + b.Property("MasterPasswordHint") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("MaxStorageGb") + .HasColumnType("INTEGER"); + + b.Property("Name") + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("Premium") + .HasColumnType("INTEGER"); + + b.Property("PremiumExpirationDate") + .HasColumnType("TEXT"); + + b.Property("PrivateKey") + .HasColumnType("TEXT"); + + b.Property("PublicKey") + .HasColumnType("TEXT"); + + b.Property("ReferenceData") + .HasColumnType("TEXT"); + + b.Property("RenewalReminderDate") + .HasColumnType("TEXT"); + + b.Property("RevisionDate") + .HasColumnType("TEXT"); + + b.Property("SecurityStamp") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("TEXT"); + + b.Property("Storage") + .HasColumnType("INTEGER"); + + b.Property("TwoFactorProviders") + .HasColumnType("TEXT"); + + b.Property("TwoFactorRecoveryCode") + .HasMaxLength(32) + .HasColumnType("TEXT"); + + b.Property("UnknownDeviceVerificationEnabled") + .HasColumnType("INTEGER"); + + b.Property("UsesKeyConnector") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.ToTable("User", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.AccessPolicy", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("CreationDate") + .HasColumnType("TEXT"); + + b.Property("Discriminator") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Read") + .HasColumnType("INTEGER"); + + b.Property("RevisionDate") + .HasColumnType("TEXT"); + + b.Property("Write") + .HasColumnType("INTEGER"); + + b.HasKey("Id") + .HasAnnotation("SqlServer:Clustered", true); + + b.ToTable("AccessPolicy", (string)null); + + b.HasDiscriminator("Discriminator").HasValue("AccessPolicy"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ApiKey", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("ClientSecret") + .HasMaxLength(30) + .HasColumnType("TEXT"); + + b.Property("CreationDate") + .HasColumnType("TEXT"); + + b.Property("EncryptedPayload") + .HasMaxLength(4000) + .HasColumnType("TEXT"); + + b.Property("ExpireAt") + .HasColumnType("TEXT"); + + b.Property("Key") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(200) + .HasColumnType("TEXT"); + + b.Property("RevisionDate") + .HasColumnType("TEXT"); + + b.Property("Scope") + .HasMaxLength(4000) + .HasColumnType("TEXT"); + + b.Property("ServiceAccountId") + .HasColumnType("TEXT"); + + b.HasKey("Id") + .HasAnnotation("SqlServer:Clustered", true); + + b.HasIndex("ServiceAccountId") + .HasAnnotation("SqlServer:Clustered", false); + + b.ToTable("ApiKey", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Project", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("CreationDate") + .HasColumnType("TEXT"); + + b.Property("DeletedDate") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("OrganizationId") + .HasColumnType("TEXT"); + + b.Property("RevisionDate") + .HasColumnType("TEXT"); + + b.HasKey("Id") + .HasAnnotation("SqlServer:Clustered", true); + + b.HasIndex("DeletedDate") + .HasAnnotation("SqlServer:Clustered", false); + + b.HasIndex("OrganizationId") + .HasAnnotation("SqlServer:Clustered", false); + + b.ToTable("Project", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Secret", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("CreationDate") + .HasColumnType("TEXT"); + + b.Property("DeletedDate") + .HasColumnType("TEXT"); + + b.Property("Key") + .HasColumnType("TEXT"); + + b.Property("Note") + .HasColumnType("TEXT"); + + b.Property("OrganizationId") + .HasColumnType("TEXT"); + + b.Property("RevisionDate") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("Id") + .HasAnnotation("SqlServer:Clustered", true); + + b.HasIndex("DeletedDate") + .HasAnnotation("SqlServer:Clustered", false); + + b.HasIndex("OrganizationId") + .HasAnnotation("SqlServer:Clustered", false); + + b.ToTable("Secret", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccount", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("CreationDate") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("OrganizationId") + .HasColumnType("TEXT"); + + b.Property("RevisionDate") + .HasColumnType("TEXT"); + + b.HasKey("Id") + .HasAnnotation("SqlServer:Clustered", true); + + b.HasIndex("OrganizationId") + .HasAnnotation("SqlServer:Clustered", false); + + b.ToTable("ServiceAccount", (string)null); + }); + + modelBuilder.Entity("ProjectSecret", b => + { + b.Property("ProjectsId") + .HasColumnType("TEXT"); + + b.Property("SecretsId") + .HasColumnType("TEXT"); + + b.HasKey("ProjectsId", "SecretsId"); + + b.HasIndex("SecretsId"); + + b.ToTable("ProjectSecret"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.GroupProjectAccessPolicy", b => + { + b.HasBaseType("Bit.Infrastructure.EntityFramework.SecretsManager.Models.AccessPolicy"); + + b.Property("GrantedProjectId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("TEXT") + .HasColumnName("GrantedProjectId"); + + b.Property("GroupId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("TEXT") + .HasColumnName("GroupId"); + + b.HasIndex("GrantedProjectId"); + + b.HasIndex("GroupId"); + + b.HasDiscriminator().HasValue("group_project"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.GroupServiceAccountAccessPolicy", b => + { + b.HasBaseType("Bit.Infrastructure.EntityFramework.SecretsManager.Models.AccessPolicy"); + + b.Property("GrantedServiceAccountId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("TEXT") + .HasColumnName("GrantedServiceAccountId"); + + b.Property("GroupId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("TEXT") + .HasColumnName("GroupId"); + + b.HasIndex("GrantedServiceAccountId"); + + b.HasIndex("GroupId"); + + b.HasDiscriminator().HasValue("group_service_account"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccountProjectAccessPolicy", b => + { + b.HasBaseType("Bit.Infrastructure.EntityFramework.SecretsManager.Models.AccessPolicy"); + + b.Property("GrantedProjectId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("TEXT") + .HasColumnName("GrantedProjectId"); + + b.Property("ServiceAccountId") + .HasColumnType("TEXT") + .HasColumnName("ServiceAccountId"); + + b.HasIndex("GrantedProjectId"); + + b.HasIndex("ServiceAccountId"); + + b.HasDiscriminator().HasValue("service_account_project"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.UserProjectAccessPolicy", b => + { + b.HasBaseType("Bit.Infrastructure.EntityFramework.SecretsManager.Models.AccessPolicy"); + + b.Property("GrantedProjectId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("TEXT") + .HasColumnName("GrantedProjectId"); + + b.Property("OrganizationUserId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("TEXT") + .HasColumnName("OrganizationUserId"); + + b.HasIndex("GrantedProjectId"); + + b.HasIndex("OrganizationUserId"); + + b.HasDiscriminator().HasValue("user_project"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.UserServiceAccountAccessPolicy", b => + { + b.HasBaseType("Bit.Infrastructure.EntityFramework.SecretsManager.Models.AccessPolicy"); + + b.Property("GrantedServiceAccountId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("TEXT") + .HasColumnName("GrantedServiceAccountId"); + + b.Property("OrganizationUserId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("TEXT") + .HasColumnName("OrganizationUserId"); + + b.HasIndex("GrantedServiceAccountId"); + + b.HasIndex("OrganizationUserId"); + + b.HasDiscriminator().HasValue("user_service_account"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.AuthRequest", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Device", "ResponseDevice") + .WithMany() + .HasForeignKey("ResponseDeviceId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ResponseDevice"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Cipher", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Ciphers") + .HasForeignKey("OrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("Ciphers") + .HasForeignKey("UserId"); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Collection", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionCipher", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Cipher", "Cipher") + .WithMany("CollectionCiphers") + .HasForeignKey("CipherId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Collection", "Collection") + .WithMany("CollectionCiphers") + .HasForeignKey("CollectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Cipher"); + + b.Navigation("Collection"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionGroup", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Collection", "Collection") + .WithMany("CollectionGroups") + .HasForeignKey("CollectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Group", "Group") + .WithMany() + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Collection"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.CollectionUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Collection", "Collection") + .WithMany("CollectionUsers") + .HasForeignKey("CollectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", "OrganizationUser") + .WithMany("CollectionUsers") + .HasForeignKey("OrganizationUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Collection"); + + b.Navigation("OrganizationUser"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Device", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.EmergencyAccess", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "Grantee") + .WithMany() + .HasForeignKey("GranteeId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "Grantor") + .WithMany() + .HasForeignKey("GrantorId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Grantee"); + + b.Navigation("Grantor"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Folder", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("Folders") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Group", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Groups") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.GroupUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Group", "Group") + .WithMany("GroupUsers") + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", "OrganizationUser") + .WithMany("GroupUsers") + .HasForeignKey("OrganizationUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Group"); + + b.Navigation("OrganizationUser"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationApiKey", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("ApiKeys") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationConnection", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Connections") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationSponsorship", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "SponsoredOrganization") + .WithMany() + .HasForeignKey("SponsoredOrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "SponsoringOrganization") + .WithMany() + .HasForeignKey("SponsoringOrganizationId"); + + b.Navigation("SponsoredOrganization"); + + b.Navigation("SponsoringOrganization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("OrganizationUsers") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("OrganizationUsers") + .HasForeignKey("UserId"); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Policy", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Policies") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderOrganization", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Provider", "Provider") + .WithMany() + .HasForeignKey("ProviderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + + b.Navigation("Provider"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Provider", "Provider") + .WithMany() + .HasForeignKey("ProviderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany() + .HasForeignKey("UserId"); + + b.Navigation("Provider"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Send", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany() + .HasForeignKey("UserId"); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoConfig", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("SsoConfigs") + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoUser", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("SsoUsers") + .HasForeignKey("OrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("SsoUsers") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Transaction", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany("Transactions") + .HasForeignKey("OrganizationId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.User", "User") + .WithMany("Transactions") + .HasForeignKey("UserId"); + + b.Navigation("Organization"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ApiKey", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccount", "ServiceAccount") + .WithMany() + .HasForeignKey("ServiceAccountId"); + + b.Navigation("ServiceAccount"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Project", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Secret", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccount", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("ProjectSecret", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Project", null) + .WithMany() + .HasForeignKey("ProjectsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Secret", null) + .WithMany() + .HasForeignKey("SecretsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.GroupProjectAccessPolicy", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Project", "GrantedProject") + .WithMany("GroupAccessPolicies") + .HasForeignKey("GrantedProjectId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Group", "Group") + .WithMany() + .HasForeignKey("GroupId"); + + b.Navigation("GrantedProject"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.GroupServiceAccountAccessPolicy", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccount", "GrantedServiceAccount") + .WithMany("GroupAccessPolicies") + .HasForeignKey("GrantedServiceAccountId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Group", "Group") + .WithMany() + .HasForeignKey("GroupId"); + + b.Navigation("GrantedServiceAccount"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccountProjectAccessPolicy", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Project", "GrantedProject") + .WithMany("ServiceAccountAccessPolicies") + .HasForeignKey("GrantedProjectId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccount", "ServiceAccount") + .WithMany() + .HasForeignKey("ServiceAccountId"); + + b.Navigation("GrantedProject"); + + b.Navigation("ServiceAccount"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.UserProjectAccessPolicy", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Project", "GrantedProject") + .WithMany("UserAccessPolicies") + .HasForeignKey("GrantedProjectId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", "OrganizationUser") + .WithMany() + .HasForeignKey("OrganizationUserId"); + + b.Navigation("GrantedProject"); + + b.Navigation("OrganizationUser"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.UserServiceAccountAccessPolicy", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccount", "GrantedServiceAccount") + .WithMany("UserAccessPolicies") + .HasForeignKey("GrantedServiceAccountId"); + + b.HasOne("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", "OrganizationUser") + .WithMany() + .HasForeignKey("OrganizationUserId"); + + b.Navigation("GrantedServiceAccount"); + + b.Navigation("OrganizationUser"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Cipher", b => + { + b.Navigation("CollectionCiphers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Collection", b => + { + b.Navigation("CollectionCiphers"); + + b.Navigation("CollectionGroups"); + + b.Navigation("CollectionUsers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Group", b => + { + b.Navigation("GroupUsers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Organization", b => + { + b.Navigation("ApiKeys"); + + b.Navigation("Ciphers"); + + b.Navigation("Connections"); + + b.Navigation("Groups"); + + b.Navigation("OrganizationUsers"); + + b.Navigation("Policies"); + + b.Navigation("SsoConfigs"); + + b.Navigation("SsoUsers"); + + b.Navigation("Transactions"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", b => + { + b.Navigation("CollectionUsers"); + + b.Navigation("GroupUsers"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.User", b => + { + b.Navigation("Ciphers"); + + b.Navigation("Folders"); + + b.Navigation("OrganizationUsers"); + + b.Navigation("SsoUsers"); + + b.Navigation("Transactions"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Project", b => + { + b.Navigation("GroupAccessPolicies"); + + b.Navigation("ServiceAccountAccessPolicies"); + + b.Navigation("UserAccessPolicies"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccount", b => + { + b.Navigation("GroupAccessPolicies"); + + b.Navigation("UserAccessPolicies"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/util/SqliteMigrations/Migrations/20230201192604_LastUserDates.cs b/util/SqliteMigrations/Migrations/20230201192604_LastUserDates.cs new file mode 100644 index 0000000000..fb86391032 --- /dev/null +++ b/util/SqliteMigrations/Migrations/20230201192604_LastUserDates.cs @@ -0,0 +1,54 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Bit.SqliteMigrations.Migrations; + +public partial class LastUserDates : Migration +{ + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "LastEmailChangeDate", + table: "User", + type: "TEXT", + nullable: true); + + migrationBuilder.AddColumn( + name: "LastKdfChangeDate", + table: "User", + type: "TEXT", + nullable: true); + + migrationBuilder.AddColumn( + name: "LastKeyRotationDate", + table: "User", + type: "TEXT", + nullable: true); + + migrationBuilder.AddColumn( + name: "LastPasswordChangeDate", + table: "User", + type: "TEXT", + nullable: true); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "LastEmailChangeDate", + table: "User"); + + migrationBuilder.DropColumn( + name: "LastKdfChangeDate", + table: "User"); + + migrationBuilder.DropColumn( + name: "LastKeyRotationDate", + table: "User"); + + migrationBuilder.DropColumn( + name: "LastPasswordChangeDate", + table: "User"); + } +} diff --git a/util/SqliteMigrations/Migrations/DatabaseContextModelSnapshot.cs b/util/SqliteMigrations/Migrations/DatabaseContextModelSnapshot.cs index aa6dd97ba9..bba1dd1559 100644 --- a/util/SqliteMigrations/Migrations/DatabaseContextModelSnapshot.cs +++ b/util/SqliteMigrations/Migrations/DatabaseContextModelSnapshot.cs @@ -17,80 +17,6 @@ namespace Bit.SqliteMigrations.Migrations #pragma warning disable 612, 618 modelBuilder.HasAnnotation("ProductVersion", "6.0.12"); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.AccessPolicy", b => - { - b.Property("Id") - .HasColumnType("TEXT"); - - b.Property("CreationDate") - .HasColumnType("TEXT"); - - b.Property("Discriminator") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("Read") - .HasColumnType("INTEGER"); - - b.Property("RevisionDate") - .HasColumnType("TEXT"); - - b.Property("Write") - .HasColumnType("INTEGER"); - - b.HasKey("Id") - .HasAnnotation("SqlServer:Clustered", true); - - b.ToTable("AccessPolicy", (string)null); - - b.HasDiscriminator("Discriminator").HasValue("AccessPolicy"); - }); - - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ApiKey", b => - { - b.Property("Id") - .HasColumnType("TEXT"); - - b.Property("ClientSecret") - .HasMaxLength(30) - .HasColumnType("TEXT"); - - b.Property("CreationDate") - .HasColumnType("TEXT"); - - b.Property("EncryptedPayload") - .HasMaxLength(4000) - .HasColumnType("TEXT"); - - b.Property("ExpireAt") - .HasColumnType("TEXT"); - - b.Property("Key") - .HasColumnType("TEXT"); - - b.Property("Name") - .HasMaxLength(200) - .HasColumnType("TEXT"); - - b.Property("RevisionDate") - .HasColumnType("TEXT"); - - b.Property("Scope") - .HasMaxLength(4000) - .HasColumnType("TEXT"); - - b.Property("ServiceAccountId") - .HasColumnType("TEXT"); - - b.HasKey("Id") - .HasAnnotation("SqlServer:Clustered", true); - - b.HasIndex("ServiceAccountId") - .HasAnnotation("SqlServer:Clustered", false); - - b.ToTable("ApiKey", (string)null); - }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.AuthRequest", b => { b.Property("Id") @@ -828,6 +754,9 @@ namespace Bit.SqliteMigrations.Migrations b.Property("AccessAll") .HasColumnType("INTEGER"); + b.Property("AccessSecretsManager") + .HasColumnType("INTEGER"); + b.Property("CreationDate") .HasColumnType("TEXT"); @@ -902,38 +831,6 @@ namespace Bit.SqliteMigrations.Migrations b.ToTable("Policy", (string)null); }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Project", b => - { - b.Property("Id") - .HasColumnType("TEXT"); - - b.Property("CreationDate") - .HasColumnType("TEXT"); - - b.Property("DeletedDate") - .HasColumnType("TEXT"); - - b.Property("Name") - .HasColumnType("TEXT"); - - b.Property("OrganizationId") - .HasColumnType("TEXT"); - - b.Property("RevisionDate") - .HasColumnType("TEXT"); - - b.HasKey("Id") - .HasAnnotation("SqlServer:Clustered", true); - - b.HasIndex("DeletedDate") - .HasAnnotation("SqlServer:Clustered", false); - - b.HasIndex("OrganizationId") - .HasAnnotation("SqlServer:Clustered", false); - - b.ToTable("Project", (string)null); - }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Provider", b => { b.Property("Id") @@ -1062,44 +959,6 @@ namespace Bit.SqliteMigrations.Migrations b.ToTable("ProviderUser", (string)null); }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Secret", b => - { - b.Property("Id") - .HasColumnType("TEXT"); - - b.Property("CreationDate") - .HasColumnType("TEXT"); - - b.Property("DeletedDate") - .HasColumnType("TEXT"); - - b.Property("Key") - .HasColumnType("TEXT"); - - b.Property("Note") - .HasColumnType("TEXT"); - - b.Property("OrganizationId") - .HasColumnType("TEXT"); - - b.Property("RevisionDate") - .HasColumnType("TEXT"); - - b.Property("Value") - .HasColumnType("TEXT"); - - b.HasKey("Id") - .HasAnnotation("SqlServer:Clustered", true); - - b.HasIndex("DeletedDate") - .HasAnnotation("SqlServer:Clustered", false); - - b.HasIndex("OrganizationId") - .HasAnnotation("SqlServer:Clustered", false); - - b.ToTable("Secret", (string)null); - }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Send", b => { b.Property("Id") @@ -1157,32 +1016,6 @@ namespace Bit.SqliteMigrations.Migrations b.ToTable("Send", (string)null); }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ServiceAccount", b => - { - b.Property("Id") - .HasColumnType("TEXT"); - - b.Property("CreationDate") - .HasColumnType("TEXT"); - - b.Property("Name") - .HasColumnType("TEXT"); - - b.Property("OrganizationId") - .HasColumnType("TEXT"); - - b.Property("RevisionDate") - .HasColumnType("TEXT"); - - b.HasKey("Id") - .HasAnnotation("SqlServer:Clustered", true); - - b.HasIndex("OrganizationId") - .HasAnnotation("SqlServer:Clustered", false); - - b.ToTable("ServiceAccount", (string)null); - }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoConfig", b => { b.Property("Id") @@ -1387,9 +1220,21 @@ namespace Bit.SqliteMigrations.Migrations b.Property("Key") .HasColumnType("TEXT"); + b.Property("LastEmailChangeDate") + .HasColumnType("TEXT"); + b.Property("LastFailedLoginDate") .HasColumnType("TEXT"); + b.Property("LastKdfChangeDate") + .HasColumnType("TEXT"); + + b.Property("LastKeyRotationDate") + .HasColumnType("TEXT"); + + b.Property("LastPasswordChangeDate") + .HasColumnType("TEXT"); + b.Property("LicenseKey") .HasMaxLength(100) .HasColumnType("TEXT"); @@ -1456,6 +1301,176 @@ namespace Bit.SqliteMigrations.Migrations b.ToTable("User", (string)null); }); + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.AccessPolicy", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("CreationDate") + .HasColumnType("TEXT"); + + b.Property("Discriminator") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Read") + .HasColumnType("INTEGER"); + + b.Property("RevisionDate") + .HasColumnType("TEXT"); + + b.Property("Write") + .HasColumnType("INTEGER"); + + b.HasKey("Id") + .HasAnnotation("SqlServer:Clustered", true); + + b.ToTable("AccessPolicy", (string)null); + + b.HasDiscriminator("Discriminator").HasValue("AccessPolicy"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ApiKey", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("ClientSecret") + .HasMaxLength(30) + .HasColumnType("TEXT"); + + b.Property("CreationDate") + .HasColumnType("TEXT"); + + b.Property("EncryptedPayload") + .HasMaxLength(4000) + .HasColumnType("TEXT"); + + b.Property("ExpireAt") + .HasColumnType("TEXT"); + + b.Property("Key") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(200) + .HasColumnType("TEXT"); + + b.Property("RevisionDate") + .HasColumnType("TEXT"); + + b.Property("Scope") + .HasMaxLength(4000) + .HasColumnType("TEXT"); + + b.Property("ServiceAccountId") + .HasColumnType("TEXT"); + + b.HasKey("Id") + .HasAnnotation("SqlServer:Clustered", true); + + b.HasIndex("ServiceAccountId") + .HasAnnotation("SqlServer:Clustered", false); + + b.ToTable("ApiKey", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Project", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("CreationDate") + .HasColumnType("TEXT"); + + b.Property("DeletedDate") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("OrganizationId") + .HasColumnType("TEXT"); + + b.Property("RevisionDate") + .HasColumnType("TEXT"); + + b.HasKey("Id") + .HasAnnotation("SqlServer:Clustered", true); + + b.HasIndex("DeletedDate") + .HasAnnotation("SqlServer:Clustered", false); + + b.HasIndex("OrganizationId") + .HasAnnotation("SqlServer:Clustered", false); + + b.ToTable("Project", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Secret", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("CreationDate") + .HasColumnType("TEXT"); + + b.Property("DeletedDate") + .HasColumnType("TEXT"); + + b.Property("Key") + .HasColumnType("TEXT"); + + b.Property("Note") + .HasColumnType("TEXT"); + + b.Property("OrganizationId") + .HasColumnType("TEXT"); + + b.Property("RevisionDate") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("Id") + .HasAnnotation("SqlServer:Clustered", true); + + b.HasIndex("DeletedDate") + .HasAnnotation("SqlServer:Clustered", false); + + b.HasIndex("OrganizationId") + .HasAnnotation("SqlServer:Clustered", false); + + b.ToTable("Secret", (string)null); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccount", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("CreationDate") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("OrganizationId") + .HasColumnType("TEXT"); + + b.Property("RevisionDate") + .HasColumnType("TEXT"); + + b.HasKey("Id") + .HasAnnotation("SqlServer:Clustered", true); + + b.HasIndex("OrganizationId") + .HasAnnotation("SqlServer:Clustered", false); + + b.ToTable("ServiceAccount", (string)null); + }); + modelBuilder.Entity("ProjectSecret", b => { b.Property("ProjectsId") @@ -1471,9 +1486,9 @@ namespace Bit.SqliteMigrations.Migrations b.ToTable("ProjectSecret"); }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.GroupProjectAccessPolicy", b => + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.GroupProjectAccessPolicy", b => { - b.HasBaseType("Bit.Infrastructure.EntityFramework.Models.AccessPolicy"); + b.HasBaseType("Bit.Infrastructure.EntityFramework.SecretsManager.Models.AccessPolicy"); b.Property("GrantedProjectId") .ValueGeneratedOnUpdateSometimes() @@ -1492,9 +1507,9 @@ namespace Bit.SqliteMigrations.Migrations b.HasDiscriminator().HasValue("group_project"); }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.GroupServiceAccountAccessPolicy", b => + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.GroupServiceAccountAccessPolicy", b => { - b.HasBaseType("Bit.Infrastructure.EntityFramework.Models.AccessPolicy"); + b.HasBaseType("Bit.Infrastructure.EntityFramework.SecretsManager.Models.AccessPolicy"); b.Property("GrantedServiceAccountId") .ValueGeneratedOnUpdateSometimes() @@ -1513,9 +1528,9 @@ namespace Bit.SqliteMigrations.Migrations b.HasDiscriminator().HasValue("group_service_account"); }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ServiceAccountProjectAccessPolicy", b => + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccountProjectAccessPolicy", b => { - b.HasBaseType("Bit.Infrastructure.EntityFramework.Models.AccessPolicy"); + b.HasBaseType("Bit.Infrastructure.EntityFramework.SecretsManager.Models.AccessPolicy"); b.Property("GrantedProjectId") .ValueGeneratedOnUpdateSometimes() @@ -1533,9 +1548,9 @@ namespace Bit.SqliteMigrations.Migrations b.HasDiscriminator().HasValue("service_account_project"); }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.UserProjectAccessPolicy", b => + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.UserProjectAccessPolicy", b => { - b.HasBaseType("Bit.Infrastructure.EntityFramework.Models.AccessPolicy"); + b.HasBaseType("Bit.Infrastructure.EntityFramework.SecretsManager.Models.AccessPolicy"); b.Property("GrantedProjectId") .ValueGeneratedOnUpdateSometimes() @@ -1554,9 +1569,9 @@ namespace Bit.SqliteMigrations.Migrations b.HasDiscriminator().HasValue("user_project"); }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.UserServiceAccountAccessPolicy", b => + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.UserServiceAccountAccessPolicy", b => { - b.HasBaseType("Bit.Infrastructure.EntityFramework.Models.AccessPolicy"); + b.HasBaseType("Bit.Infrastructure.EntityFramework.SecretsManager.Models.AccessPolicy"); b.Property("GrantedServiceAccountId") .ValueGeneratedOnUpdateSometimes() @@ -1575,15 +1590,6 @@ namespace Bit.SqliteMigrations.Migrations b.HasDiscriminator().HasValue("user_service_account"); }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ApiKey", b => - { - b.HasOne("Bit.Infrastructure.EntityFramework.Models.ServiceAccount", "ServiceAccount") - .WithMany() - .HasForeignKey("ServiceAccountId"); - - b.Navigation("ServiceAccount"); - }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.AuthRequest", b => { b.HasOne("Bit.Infrastructure.EntityFramework.Models.Device", "ResponseDevice") @@ -1818,17 +1824,6 @@ namespace Bit.SqliteMigrations.Migrations b.Navigation("Organization"); }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Project", b => - { - b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") - .WithMany() - .HasForeignKey("OrganizationId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Organization"); - }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ProviderOrganization", b => { b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") @@ -1865,17 +1860,6 @@ namespace Bit.SqliteMigrations.Migrations b.Navigation("User"); }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Secret", b => - { - b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") - .WithMany() - .HasForeignKey("OrganizationId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Organization"); - }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Send", b => { b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") @@ -1891,17 +1875,6 @@ namespace Bit.SqliteMigrations.Migrations b.Navigation("User"); }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ServiceAccount", b => - { - b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") - .WithMany() - .HasForeignKey("OrganizationId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Organization"); - }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.SsoConfig", b => { b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") @@ -1945,24 +1918,66 @@ namespace Bit.SqliteMigrations.Migrations b.Navigation("User"); }); + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ApiKey", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccount", "ServiceAccount") + .WithMany() + .HasForeignKey("ServiceAccountId"); + + b.Navigation("ServiceAccount"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Project", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Secret", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccount", b => + { + b.HasOne("Bit.Infrastructure.EntityFramework.Models.Organization", "Organization") + .WithMany() + .HasForeignKey("OrganizationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Organization"); + }); + modelBuilder.Entity("ProjectSecret", b => { - b.HasOne("Bit.Infrastructure.EntityFramework.Models.Project", null) + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Project", null) .WithMany() .HasForeignKey("ProjectsId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); - b.HasOne("Bit.Infrastructure.EntityFramework.Models.Secret", null) + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Secret", null) .WithMany() .HasForeignKey("SecretsId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.GroupProjectAccessPolicy", b => + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.GroupProjectAccessPolicy", b => { - b.HasOne("Bit.Infrastructure.EntityFramework.Models.Project", "GrantedProject") + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Project", "GrantedProject") .WithMany("GroupAccessPolicies") .HasForeignKey("GrantedProjectId"); @@ -1975,10 +1990,10 @@ namespace Bit.SqliteMigrations.Migrations b.Navigation("Group"); }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.GroupServiceAccountAccessPolicy", b => + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.GroupServiceAccountAccessPolicy", b => { - b.HasOne("Bit.Infrastructure.EntityFramework.Models.ServiceAccount", "GrantedServiceAccount") - .WithMany() + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccount", "GrantedServiceAccount") + .WithMany("GroupAccessPolicies") .HasForeignKey("GrantedServiceAccountId"); b.HasOne("Bit.Infrastructure.EntityFramework.Models.Group", "Group") @@ -1990,13 +2005,13 @@ namespace Bit.SqliteMigrations.Migrations b.Navigation("Group"); }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.ServiceAccountProjectAccessPolicy", b => + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccountProjectAccessPolicy", b => { - b.HasOne("Bit.Infrastructure.EntityFramework.Models.Project", "GrantedProject") + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Project", "GrantedProject") .WithMany("ServiceAccountAccessPolicies") .HasForeignKey("GrantedProjectId"); - b.HasOne("Bit.Infrastructure.EntityFramework.Models.ServiceAccount", "ServiceAccount") + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccount", "ServiceAccount") .WithMany() .HasForeignKey("ServiceAccountId"); @@ -2005,9 +2020,9 @@ namespace Bit.SqliteMigrations.Migrations b.Navigation("ServiceAccount"); }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.UserProjectAccessPolicy", b => + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.UserProjectAccessPolicy", b => { - b.HasOne("Bit.Infrastructure.EntityFramework.Models.Project", "GrantedProject") + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Project", "GrantedProject") .WithMany("UserAccessPolicies") .HasForeignKey("GrantedProjectId"); @@ -2020,10 +2035,10 @@ namespace Bit.SqliteMigrations.Migrations b.Navigation("OrganizationUser"); }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.UserServiceAccountAccessPolicy", b => + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.UserServiceAccountAccessPolicy", b => { - b.HasOne("Bit.Infrastructure.EntityFramework.Models.ServiceAccount", "GrantedServiceAccount") - .WithMany() + b.HasOne("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccount", "GrantedServiceAccount") + .WithMany("UserAccessPolicies") .HasForeignKey("GrantedServiceAccountId"); b.HasOne("Bit.Infrastructure.EntityFramework.Models.OrganizationUser", "OrganizationUser") @@ -2082,15 +2097,6 @@ namespace Bit.SqliteMigrations.Migrations b.Navigation("GroupUsers"); }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.Project", b => - { - b.Navigation("GroupAccessPolicies"); - - b.Navigation("ServiceAccountAccessPolicies"); - - b.Navigation("UserAccessPolicies"); - }); - modelBuilder.Entity("Bit.Infrastructure.EntityFramework.Models.User", b => { b.Navigation("Ciphers"); @@ -2103,6 +2109,22 @@ namespace Bit.SqliteMigrations.Migrations b.Navigation("Transactions"); }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.Project", b => + { + b.Navigation("GroupAccessPolicies"); + + b.Navigation("ServiceAccountAccessPolicies"); + + b.Navigation("UserAccessPolicies"); + }); + + modelBuilder.Entity("Bit.Infrastructure.EntityFramework.SecretsManager.Models.ServiceAccount", b => + { + b.Navigation("GroupAccessPolicies"); + + b.Navigation("UserAccessPolicies"); + }); #pragma warning restore 612, 618 } }