From 5941e830d2f1186ddc5c8ffb179096df203856bd Mon Sep 17 00:00:00 2001 From: Mick Letofsky Date: Fri, 30 Jan 2026 16:03:56 +0100 Subject: [PATCH] Refactor to correctly implement statics and remove hardcoded organization keys (#6924) --- .../GroupsControllerPerformanceTests.cs | 11 ++- ...nizationUsersControllerPerformanceTests.cs | 79 +++++++++++++------ ...OrganizationsControllerPerformanceTests.cs | 19 +++-- .../RustSdkCipherTests.cs | 40 ++++------ util/DbSeederUtility/Program.cs | 6 +- .../ServiceCollectionExtension.cs | 2 - util/RustSdk/RustSdkService.cs | 12 +-- util/Seeder/Factories/CipherSeeder.cs | 15 +--- util/Seeder/Factories/CollectionSeeder.cs | 6 +- util/Seeder/Factories/FolderSeeder.cs | 6 +- util/Seeder/Factories/OrganizationSeeder.cs | 29 +------ util/Seeder/Factories/UserSeeder.cs | 7 +- util/Seeder/Recipes/CollectionsRecipe.cs | 2 +- util/Seeder/Recipes/GroupsRecipe.cs | 2 +- .../Recipes/OrganizationDomainRecipe.cs | 2 +- .../Recipes/OrganizationWithUsersRecipe.cs | 55 +++++++++---- .../Recipes/OrganizationWithVaultRecipe.cs | 22 +++--- util/SeederApi/Startup.cs | 1 - 18 files changed, 169 insertions(+), 147 deletions(-) diff --git a/test/Api.IntegrationTest/AdminConsole/Controllers/GroupsControllerPerformanceTests.cs b/test/Api.IntegrationTest/AdminConsole/Controllers/GroupsControllerPerformanceTests.cs index 71c6bf104c..a70be7d557 100644 --- a/test/Api.IntegrationTest/AdminConsole/Controllers/GroupsControllerPerformanceTests.cs +++ b/test/Api.IntegrationTest/AdminConsole/Controllers/GroupsControllerPerformanceTests.cs @@ -1,11 +1,14 @@ using System.Net; using System.Text; using System.Text.Json; +using AutoMapper; using Bit.Api.AdminConsole.Models.Request; using Bit.Api.IntegrationTest.Factories; using Bit.Api.IntegrationTest.Helpers; using Bit.Api.Models.Request; +using Bit.Core.Entities; using Bit.Seeder.Recipes; +using Microsoft.AspNetCore.Identity; using Xunit; using Xunit.Abstractions; @@ -26,7 +29,9 @@ public class GroupsControllerPerformanceTests(ITestOutputHelper testOutputHelper var client = factory.CreateClient(); var db = factory.GetDatabaseContext(); - var orgSeeder = new OrganizationWithUsersRecipe(db); + var mapper = factory.GetService(); + var passwordHasher = factory.GetService>(); + var orgSeeder = new OrganizationWithUsersRecipe(db, mapper, passwordHasher); var collectionsSeeder = new CollectionsRecipe(db); var groupsSeeder = new GroupsRecipe(db); @@ -34,8 +39,8 @@ public class GroupsControllerPerformanceTests(ITestOutputHelper testOutputHelper var orgId = orgSeeder.Seed(name: "Org", domain: domain, users: userCount); var orgUserIds = db.OrganizationUsers.Where(ou => ou.OrganizationId == orgId).Select(ou => ou.Id).ToList(); - var collectionIds = collectionsSeeder.AddToOrganization(orgId, collectionCount, orgUserIds, 0); - var groupIds = groupsSeeder.AddToOrganization(orgId, 1, orgUserIds, 0); + var collectionIds = collectionsSeeder.Seed(orgId, collectionCount, orgUserIds, 0); + var groupIds = groupsSeeder.Seed(orgId, 1, orgUserIds, 0); var groupId = groupIds.First(); diff --git a/test/Api.IntegrationTest/AdminConsole/Controllers/OrganizationUsersControllerPerformanceTests.cs b/test/Api.IntegrationTest/AdminConsole/Controllers/OrganizationUsersControllerPerformanceTests.cs index fc64930777..322fd62bd7 100644 --- a/test/Api.IntegrationTest/AdminConsole/Controllers/OrganizationUsersControllerPerformanceTests.cs +++ b/test/Api.IntegrationTest/AdminConsole/Controllers/OrganizationUsersControllerPerformanceTests.cs @@ -1,13 +1,16 @@ using System.Net; using System.Text; using System.Text.Json; +using AutoMapper; using Bit.Api.AdminConsole.Models.Request.Organizations; using Bit.Api.IntegrationTest.Factories; using Bit.Api.IntegrationTest.Helpers; using Bit.Api.Models.Request; +using Bit.Core.Entities; using Bit.Core.Enums; using Bit.Core.Models.Data; using Bit.Seeder.Recipes; +using Microsoft.AspNetCore.Identity; using Xunit; using Xunit.Abstractions; @@ -28,7 +31,9 @@ public class OrganizationUsersControllerPerformanceTests(ITestOutputHelper testO var client = factory.CreateClient(); var db = factory.GetDatabaseContext(); - var orgSeeder = new OrganizationWithUsersRecipe(db); + var mapper = factory.GetService(); + var passwordHasher = factory.GetService>(); + var orgSeeder = new OrganizationWithUsersRecipe(db, mapper, passwordHasher); var collectionsSeeder = new CollectionsRecipe(db); var groupsSeeder = new GroupsRecipe(db); @@ -37,8 +42,8 @@ public class OrganizationUsersControllerPerformanceTests(ITestOutputHelper testO var orgId = orgSeeder.Seed(name: "Org", domain: domain, users: seats); var orgUserIds = db.OrganizationUsers.Where(ou => ou.OrganizationId == orgId).Select(ou => ou.Id).ToList(); - collectionsSeeder.AddToOrganization(orgId, 10, orgUserIds); - groupsSeeder.AddToOrganization(orgId, 5, orgUserIds); + collectionsSeeder.Seed(orgId, 10, orgUserIds); + groupsSeeder.Seed(orgId, 5, orgUserIds); await PerformanceTestHelpers.AuthenticateClientAsync(factory, client, $"owner@{domain}"); @@ -64,7 +69,9 @@ public class OrganizationUsersControllerPerformanceTests(ITestOutputHelper testO var client = factory.CreateClient(); var db = factory.GetDatabaseContext(); - var orgSeeder = new OrganizationWithUsersRecipe(db); + var mapper = factory.GetService(); + var passwordHasher = factory.GetService>(); + var orgSeeder = new OrganizationWithUsersRecipe(db, mapper, passwordHasher); var collectionsSeeder = new CollectionsRecipe(db); var groupsSeeder = new GroupsRecipe(db); @@ -72,8 +79,8 @@ public class OrganizationUsersControllerPerformanceTests(ITestOutputHelper testO var orgId = orgSeeder.Seed(name: "Org", domain: domain, users: seats); var orgUserIds = db.OrganizationUsers.Where(ou => ou.OrganizationId == orgId).Select(ou => ou.Id).ToList(); - collectionsSeeder.AddToOrganization(orgId, 10, orgUserIds); - groupsSeeder.AddToOrganization(orgId, 5, orgUserIds); + collectionsSeeder.Seed(orgId, 10, orgUserIds); + groupsSeeder.Seed(orgId, 5, orgUserIds); await PerformanceTestHelpers.AuthenticateClientAsync(factory, client, $"owner@{domain}"); @@ -98,14 +105,16 @@ public class OrganizationUsersControllerPerformanceTests(ITestOutputHelper testO var client = factory.CreateClient(); var db = factory.GetDatabaseContext(); - var orgSeeder = new OrganizationWithUsersRecipe(db); + var mapper = factory.GetService(); + var passwordHasher = factory.GetService>(); + var orgSeeder = new OrganizationWithUsersRecipe(db, mapper, passwordHasher); var groupsSeeder = new GroupsRecipe(db); var domain = OrganizationTestHelpers.GenerateRandomDomain(); var orgId = orgSeeder.Seed(name: "Org", domain: domain, users: 1); var orgUserId = db.OrganizationUsers.Where(ou => ou.OrganizationId == orgId).Select(ou => ou.Id).FirstOrDefault(); - groupsSeeder.AddToOrganization(orgId, 2, [orgUserId]); + groupsSeeder.Seed(orgId, 2, [orgUserId]); await PerformanceTestHelpers.AuthenticateClientAsync(factory, client, $"owner@{domain}"); @@ -130,7 +139,9 @@ public class OrganizationUsersControllerPerformanceTests(ITestOutputHelper testO var client = factory.CreateClient(); var db = factory.GetDatabaseContext(); - var orgSeeder = new OrganizationWithUsersRecipe(db); + var mapper = factory.GetService(); + var passwordHasher = factory.GetService>(); + var orgSeeder = new OrganizationWithUsersRecipe(db, mapper, passwordHasher); var domain = OrganizationTestHelpers.GenerateRandomDomain(); var orgId = orgSeeder.Seed(name: "Org", domain: domain, users: 1); @@ -163,7 +174,9 @@ public class OrganizationUsersControllerPerformanceTests(ITestOutputHelper testO var client = factory.CreateClient(); var db = factory.GetDatabaseContext(); - var orgSeeder = new OrganizationWithUsersRecipe(db); + var mapper = factory.GetService(); + var passwordHasher = factory.GetService>(); + var orgSeeder = new OrganizationWithUsersRecipe(db, mapper, passwordHasher); var domain = OrganizationTestHelpers.GenerateRandomDomain(); var orgId = orgSeeder.Seed( @@ -211,7 +224,9 @@ public class OrganizationUsersControllerPerformanceTests(ITestOutputHelper testO var client = factory.CreateClient(); var db = factory.GetDatabaseContext(); - var orgSeeder = new OrganizationWithUsersRecipe(db); + var mapper = factory.GetService(); + var passwordHasher = factory.GetService>(); + var orgSeeder = new OrganizationWithUsersRecipe(db, mapper, passwordHasher); var domain = OrganizationTestHelpers.GenerateRandomDomain(); var orgId = orgSeeder.Seed(name: "Org", domain: domain, users: userCount); @@ -251,7 +266,9 @@ public class OrganizationUsersControllerPerformanceTests(ITestOutputHelper testO var client = factory.CreateClient(); var db = factory.GetDatabaseContext(); - var orgSeeder = new OrganizationWithUsersRecipe(db); + var mapper = factory.GetService(); + var passwordHasher = factory.GetService>(); + var orgSeeder = new OrganizationWithUsersRecipe(db, mapper, passwordHasher); var domain = OrganizationTestHelpers.GenerateRandomDomain(); var orgId = orgSeeder.Seed( @@ -295,7 +312,9 @@ public class OrganizationUsersControllerPerformanceTests(ITestOutputHelper testO var client = factory.CreateClient(); var db = factory.GetDatabaseContext(); - var orgSeeder = new OrganizationWithUsersRecipe(db); + var mapper = factory.GetService(); + var passwordHasher = factory.GetService>(); + var orgSeeder = new OrganizationWithUsersRecipe(db, mapper, passwordHasher); var domain = OrganizationTestHelpers.GenerateRandomDomain(); var orgId = orgSeeder.Seed( @@ -339,7 +358,9 @@ public class OrganizationUsersControllerPerformanceTests(ITestOutputHelper testO var client = factory.CreateClient(); var db = factory.GetDatabaseContext(); - var orgSeeder = new OrganizationWithUsersRecipe(db); + var mapper = factory.GetService(); + var passwordHasher = factory.GetService>(); + var orgSeeder = new OrganizationWithUsersRecipe(db, mapper, passwordHasher); var domainSeeder = new OrganizationDomainRecipe(db); var domain = OrganizationTestHelpers.GenerateRandomDomain(); @@ -350,7 +371,7 @@ public class OrganizationUsersControllerPerformanceTests(ITestOutputHelper testO users: userCount, usersStatus: OrganizationUserStatusType.Confirmed); - domainSeeder.AddVerifiedDomainToOrganization(orgId, domain); + domainSeeder.Seed(orgId, domain); await PerformanceTestHelpers.AuthenticateClientAsync(factory, client, $"owner@{domain}"); @@ -384,7 +405,9 @@ public class OrganizationUsersControllerPerformanceTests(ITestOutputHelper testO var client = factory.CreateClient(); var db = factory.GetDatabaseContext(); - var orgSeeder = new OrganizationWithUsersRecipe(db); + var mapper = factory.GetService(); + var passwordHasher = factory.GetService>(); + var orgSeeder = new OrganizationWithUsersRecipe(db, mapper, passwordHasher); var collectionsSeeder = new CollectionsRecipe(db); var groupsSeeder = new GroupsRecipe(db); @@ -392,8 +415,8 @@ public class OrganizationUsersControllerPerformanceTests(ITestOutputHelper testO var orgId = orgSeeder.Seed(name: "Org", domain: domain, users: 1); var orgUserIds = db.OrganizationUsers.Where(ou => ou.OrganizationId == orgId).Select(ou => ou.Id).ToList(); - var collectionIds = collectionsSeeder.AddToOrganization(orgId, 3, orgUserIds, 0); - var groupIds = groupsSeeder.AddToOrganization(orgId, 2, orgUserIds, 0); + var collectionIds = collectionsSeeder.Seed(orgId, 3, orgUserIds, 0); + var groupIds = groupsSeeder.Seed(orgId, 2, orgUserIds, 0); await PerformanceTestHelpers.AuthenticateClientAsync(factory, client, $"owner@{domain}"); @@ -434,7 +457,9 @@ public class OrganizationUsersControllerPerformanceTests(ITestOutputHelper testO var client = factory.CreateClient(); var db = factory.GetDatabaseContext(); - var orgSeeder = new OrganizationWithUsersRecipe(db); + var mapper = factory.GetService(); + var passwordHasher = factory.GetService>(); + var orgSeeder = new OrganizationWithUsersRecipe(db, mapper, passwordHasher); var domain = OrganizationTestHelpers.GenerateRandomDomain(); var orgId = orgSeeder.Seed(name: "Org", domain: domain, users: userCount); @@ -471,7 +496,9 @@ public class OrganizationUsersControllerPerformanceTests(ITestOutputHelper testO var client = factory.CreateClient(); var db = factory.GetDatabaseContext(); - var orgSeeder = new OrganizationWithUsersRecipe(db); + var mapper = factory.GetService(); + var passwordHasher = factory.GetService>(); + var orgSeeder = new OrganizationWithUsersRecipe(db, mapper, passwordHasher); var domainSeeder = new OrganizationDomainRecipe(db); var domain = OrganizationTestHelpers.GenerateRandomDomain(); @@ -481,7 +508,7 @@ public class OrganizationUsersControllerPerformanceTests(ITestOutputHelper testO users: 2, usersStatus: OrganizationUserStatusType.Confirmed); - domainSeeder.AddVerifiedDomainToOrganization(orgId, domain); + domainSeeder.Seed(orgId, domain); await PerformanceTestHelpers.AuthenticateClientAsync(factory, client, $"owner@{domain}"); @@ -512,14 +539,16 @@ public class OrganizationUsersControllerPerformanceTests(ITestOutputHelper testO var client = factory.CreateClient(); var db = factory.GetDatabaseContext(); - var orgSeeder = new OrganizationWithUsersRecipe(db); + var mapper = factory.GetService(); + var passwordHasher = factory.GetService>(); + var orgSeeder = new OrganizationWithUsersRecipe(db, mapper, passwordHasher); var collectionsSeeder = new CollectionsRecipe(db); var domain = OrganizationTestHelpers.GenerateRandomDomain(); var orgId = orgSeeder.Seed(name: "Org", domain: domain, users: 1); var orgUserIds = db.OrganizationUsers.Where(ou => ou.OrganizationId == orgId).Select(ou => ou.Id).ToList(); - var collectionIds = collectionsSeeder.AddToOrganization(orgId, 2, orgUserIds, 0); + var collectionIds = collectionsSeeder.Seed(orgId, 2, orgUserIds, 0); await PerformanceTestHelpers.AuthenticateClientAsync(factory, client, $"owner@{domain}"); @@ -560,7 +589,9 @@ public class OrganizationUsersControllerPerformanceTests(ITestOutputHelper testO var client = factory.CreateClient(); var db = factory.GetDatabaseContext(); - var orgSeeder = new OrganizationWithUsersRecipe(db); + var mapper = factory.GetService(); + var passwordHasher = factory.GetService>(); + var orgSeeder = new OrganizationWithUsersRecipe(db, mapper, passwordHasher); var domain = OrganizationTestHelpers.GenerateRandomDomain(); var orgId = orgSeeder.Seed( diff --git a/test/Api.IntegrationTest/AdminConsole/Controllers/OrganizationsControllerPerformanceTests.cs b/test/Api.IntegrationTest/AdminConsole/Controllers/OrganizationsControllerPerformanceTests.cs index 238a9a5d53..025eacc432 100644 --- a/test/Api.IntegrationTest/AdminConsole/Controllers/OrganizationsControllerPerformanceTests.cs +++ b/test/Api.IntegrationTest/AdminConsole/Controllers/OrganizationsControllerPerformanceTests.cs @@ -1,14 +1,17 @@ using System.Net; using System.Text; using System.Text.Json; +using AutoMapper; using Bit.Api.AdminConsole.Models.Request.Organizations; using Bit.Api.Auth.Models.Request.Accounts; using Bit.Api.IntegrationTest.Factories; using Bit.Api.IntegrationTest.Helpers; using Bit.Core.AdminConsole.Models.Business.Tokenables; using Bit.Core.Billing.Enums; +using Bit.Core.Entities; using Bit.Core.Tokens; using Bit.Seeder.Recipes; +using Microsoft.AspNetCore.Identity; using Xunit; using Xunit.Abstractions; @@ -29,7 +32,9 @@ public class OrganizationsControllerPerformanceTests(ITestOutputHelper testOutpu var client = factory.CreateClient(); var db = factory.GetDatabaseContext(); - var orgSeeder = new OrganizationWithUsersRecipe(db); + var mapper = factory.GetService(); + var passwordHasher = factory.GetService>(); + var orgSeeder = new OrganizationWithUsersRecipe(db, mapper, passwordHasher); var collectionsSeeder = new CollectionsRecipe(db); var groupsSeeder = new GroupsRecipe(db); @@ -37,8 +42,8 @@ public class OrganizationsControllerPerformanceTests(ITestOutputHelper testOutpu var orgId = orgSeeder.Seed(name: "Org", domain: domain, users: userCount); var orgUserIds = db.OrganizationUsers.Where(ou => ou.OrganizationId == orgId).Select(ou => ou.Id).ToList(); - collectionsSeeder.AddToOrganization(orgId, collectionCount, orgUserIds, 0); - groupsSeeder.AddToOrganization(orgId, groupCount, orgUserIds, 0); + collectionsSeeder.Seed(orgId, collectionCount, orgUserIds, 0); + groupsSeeder.Seed(orgId, groupCount, orgUserIds, 0); await PerformanceTestHelpers.AuthenticateClientAsync(factory, client, $"owner@{domain}"); @@ -77,7 +82,9 @@ public class OrganizationsControllerPerformanceTests(ITestOutputHelper testOutpu var client = factory.CreateClient(); var db = factory.GetDatabaseContext(); - var orgSeeder = new OrganizationWithUsersRecipe(db); + var mapper = factory.GetService(); + var passwordHasher = factory.GetService>(); + var orgSeeder = new OrganizationWithUsersRecipe(db, mapper, passwordHasher); var collectionsSeeder = new CollectionsRecipe(db); var groupsSeeder = new GroupsRecipe(db); @@ -85,8 +92,8 @@ public class OrganizationsControllerPerformanceTests(ITestOutputHelper testOutpu var orgId = orgSeeder.Seed(name: "Org", domain: domain, users: userCount); var orgUserIds = db.OrganizationUsers.Where(ou => ou.OrganizationId == orgId).Select(ou => ou.Id).ToList(); - collectionsSeeder.AddToOrganization(orgId, collectionCount, orgUserIds, 0); - groupsSeeder.AddToOrganization(orgId, groupCount, orgUserIds, 0); + collectionsSeeder.Seed(orgId, collectionCount, orgUserIds, 0); + groupsSeeder.Seed(orgId, groupCount, orgUserIds, 0); await PerformanceTestHelpers.AuthenticateClientAsync(factory, client, $"owner@{domain}"); diff --git a/test/SeederApi.IntegrationTest/RustSdkCipherTests.cs b/test/SeederApi.IntegrationTest/RustSdkCipherTests.cs index 3c831c4893..7ca7a0b913 100644 --- a/test/SeederApi.IntegrationTest/RustSdkCipherTests.cs +++ b/test/SeederApi.IntegrationTest/RustSdkCipherTests.cs @@ -18,18 +18,17 @@ public class RustSdkCipherTests [Fact] public void EncryptDecrypt_LoginCipher_RoundtripPreservesPlaintext() { - var sdk = new RustSdkService(); - var orgKeys = sdk.GenerateOrganizationKeys(); + var orgKeys = RustSdkService.GenerateOrganizationKeys(); var originalCipher = CreateTestLoginCipher(); var originalJson = JsonSerializer.Serialize(originalCipher, SdkJsonOptions); - var encryptedJson = sdk.EncryptCipher(originalJson, orgKeys.Key); + var encryptedJson = RustSdkService.EncryptCipher(originalJson, orgKeys.Key); Assert.DoesNotContain("\"error\"", encryptedJson); Assert.Contains("\"name\":\"2.", encryptedJson); - var decryptedJson = sdk.DecryptCipher(encryptedJson, orgKeys.Key); + var decryptedJson = RustSdkService.DecryptCipher(encryptedJson, orgKeys.Key); Assert.DoesNotContain("\"error\"", decryptedJson); @@ -45,8 +44,7 @@ public class RustSdkCipherTests [Fact] public void EncryptCipher_WithUri_EncryptsAllFields() { - var sdk = new RustSdkService(); - var orgKeys = sdk.GenerateOrganizationKeys(); + var orgKeys = RustSdkService.GenerateOrganizationKeys(); var cipher = new CipherViewDto { @@ -66,7 +64,7 @@ public class RustSdkCipherTests }; var cipherJson = JsonSerializer.Serialize(cipher, SdkJsonOptions); - var encryptedJson = sdk.EncryptCipher(cipherJson, orgKeys.Key); + var encryptedJson = RustSdkService.EncryptCipher(cipherJson, orgKeys.Key); Assert.DoesNotContain("\"error\"", encryptedJson); Assert.DoesNotContain("Amazon Shopping", encryptedJson); @@ -77,17 +75,16 @@ public class RustSdkCipherTests [Fact] public void DecryptCipher_WithWrongKey_FailsOrProducesGarbage() { - var sdk = new RustSdkService(); - var encryptionKey = sdk.GenerateOrganizationKeys(); - var differentKey = sdk.GenerateOrganizationKeys(); + var encryptionKey = RustSdkService.GenerateOrganizationKeys(); + var differentKey = RustSdkService.GenerateOrganizationKeys(); var originalCipher = CreateTestLoginCipher(); var cipherJson = JsonSerializer.Serialize(originalCipher, SdkJsonOptions); - var encryptedJson = sdk.EncryptCipher(cipherJson, encryptionKey.Key); + var encryptedJson = RustSdkService.EncryptCipher(cipherJson, encryptionKey.Key); Assert.DoesNotContain("\"error\"", encryptedJson); - var decryptedJson = sdk.DecryptCipher(encryptedJson, differentKey.Key); + var decryptedJson = RustSdkService.DecryptCipher(encryptedJson, differentKey.Key); var decryptionFailedWithError = decryptedJson.Contains("\"error\""); if (!decryptionFailedWithError) @@ -100,8 +97,7 @@ public class RustSdkCipherTests [Fact] public void EncryptCipher_WithFields_EncryptsCustomFields() { - var sdk = new RustSdkService(); - var orgKeys = sdk.GenerateOrganizationKeys(); + var orgKeys = RustSdkService.GenerateOrganizationKeys(); var cipher = new CipherViewDto { @@ -120,13 +116,13 @@ public class RustSdkCipherTests }; var cipherJson = JsonSerializer.Serialize(cipher, SdkJsonOptions); - var encryptedJson = sdk.EncryptCipher(cipherJson, orgKeys.Key); + var encryptedJson = RustSdkService.EncryptCipher(cipherJson, orgKeys.Key); Assert.DoesNotContain("\"error\"", encryptedJson); Assert.DoesNotContain("sk-secret-api-key-12345", encryptedJson); Assert.DoesNotContain("client-id-xyz", encryptedJson); - var decryptedJson = sdk.DecryptCipher(encryptedJson, orgKeys.Key); + var decryptedJson = RustSdkService.DecryptCipher(encryptedJson, orgKeys.Key); var decrypted = JsonSerializer.Deserialize(decryptedJson, SdkJsonOptions); Assert.NotNull(decrypted?.Fields); @@ -138,13 +134,11 @@ public class RustSdkCipherTests [Fact] public void CipherSeeder_ProducesServerCompatibleFormat() { - var sdk = new RustSdkService(); - var orgKeys = sdk.GenerateOrganizationKeys(); - var seeder = new CipherSeeder(sdk); + var orgKeys = RustSdkService.GenerateOrganizationKeys(); var orgId = Guid.NewGuid(); // Create cipher using the seeder - var cipher = seeder.CreateOrganizationLoginCipher( + var cipher = CipherSeeder.CreateOrganizationLoginCipher( orgId, orgKeys.Key, name: "GitHub Account", @@ -179,11 +173,9 @@ public class RustSdkCipherTests [Fact] public void CipherSeeder_WithFields_ProducesCorrectServerFormat() { - var sdk = new RustSdkService(); - var orgKeys = sdk.GenerateOrganizationKeys(); - var seeder = new CipherSeeder(sdk); + var orgKeys = RustSdkService.GenerateOrganizationKeys(); - var cipher = seeder.CreateOrganizationLoginCipherWithFields( + var cipher = CipherSeeder.CreateOrganizationLoginCipherWithFields( Guid.NewGuid(), orgKeys.Key, name: "API Service", diff --git a/util/DbSeederUtility/Program.cs b/util/DbSeederUtility/Program.cs index 1336268de1..379f60ea1a 100644 --- a/util/DbSeederUtility/Program.cs +++ b/util/DbSeederUtility/Program.cs @@ -1,7 +1,6 @@ using AutoMapper; using Bit.Core.Entities; using Bit.Infrastructure.EntityFramework.Repositories; -using Bit.RustSDK; using Bit.Seeder.Recipes; using CommandDotNet; using Microsoft.AspNetCore.Identity; @@ -37,7 +36,9 @@ public class Program var scopedServices = scope.ServiceProvider; var db = scopedServices.GetRequiredService(); - var recipe = new OrganizationWithUsersRecipe(db); + var mapper = scopedServices.GetRequiredService(); + var passwordHasher = scopedServices.GetRequiredService>(); + var recipe = new OrganizationWithUsersRecipe(db, mapper, passwordHasher); recipe.Seed(name: name, domain: domain, users: users); } @@ -56,7 +57,6 @@ public class Program var recipe = new OrganizationWithVaultRecipe( scopedServices.GetRequiredService(), scopedServices.GetRequiredService(), - scopedServices.GetRequiredService(), scopedServices.GetRequiredService>()); recipe.Seed(args.ToOptions()); diff --git a/util/DbSeederUtility/ServiceCollectionExtension.cs b/util/DbSeederUtility/ServiceCollectionExtension.cs index f21c0b89cf..ca454c50f3 100644 --- a/util/DbSeederUtility/ServiceCollectionExtension.cs +++ b/util/DbSeederUtility/ServiceCollectionExtension.cs @@ -1,5 +1,4 @@ using Bit.Core.Entities; -using Bit.RustSDK; using Bit.SharedWeb.Utilities; using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.Identity; @@ -23,7 +22,6 @@ public static class ServiceCollectionExtension builder.AddFilter("Microsoft.EntityFrameworkCore.Model.Validation", LogLevel.Error); }); services.AddSingleton(globalSettings); - services.AddSingleton(); services.AddSingleton, PasswordHasher>(); // Add Data Protection services diff --git a/util/RustSdk/RustSdkService.cs b/util/RustSdk/RustSdkService.cs index ec3712274f..b6ada76df7 100644 --- a/util/RustSdk/RustSdkService.cs +++ b/util/RustSdk/RustSdkService.cs @@ -37,7 +37,7 @@ public class RustSdkService PropertyNameCaseInsensitive = true }; - public unsafe UserKeys GenerateUserKeys(string email, string password) + public static unsafe UserKeys GenerateUserKeys(string email, string password) { var emailBytes = StringToRustString(email); var passwordBytes = StringToRustString(password); @@ -53,7 +53,7 @@ public class RustSdkService } } - public unsafe OrganizationKeys GenerateOrganizationKeys() + public static unsafe OrganizationKeys GenerateOrganizationKeys() { var resultPtr = NativeMethods.generate_organization_keys(); @@ -62,7 +62,7 @@ public class RustSdkService return JsonSerializer.Deserialize(result, CaseInsensitiveOptions)!; } - public unsafe string GenerateUserOrganizationKey(string userKey, string orgKey) + public static unsafe string GenerateUserOrganizationKey(string userKey, string orgKey) { var userKeyBytes = StringToRustString(userKey); var orgKeyBytes = StringToRustString(orgKey); @@ -78,7 +78,7 @@ public class RustSdkService } } - public unsafe string EncryptCipher(string cipherViewJson, string symmetricKeyBase64) + public static unsafe string EncryptCipher(string cipherViewJson, string symmetricKeyBase64) { var cipherViewBytes = StringToRustString(cipherViewJson); var keyBytes = StringToRustString(symmetricKeyBase64); @@ -92,7 +92,7 @@ public class RustSdkService } } - public unsafe string DecryptCipher(string cipherJson, string symmetricKeyBase64) + public static unsafe string DecryptCipher(string cipherJson, string symmetricKeyBase64) { var cipherBytes = StringToRustString(cipherJson); var keyBytes = StringToRustString(symmetricKeyBase64); @@ -110,7 +110,7 @@ public class RustSdkService /// Encrypts a plaintext string using the provided symmetric key. /// Returns an EncString in format "2.{iv}|{data}|{mac}". /// - public unsafe string EncryptString(string plaintext, string symmetricKeyBase64) + public static unsafe string EncryptString(string plaintext, string symmetricKeyBase64) { var plaintextBytes = StringToRustString(plaintext); var keyBytes = StringToRustString(symmetricKeyBase64); diff --git a/util/Seeder/Factories/CipherSeeder.cs b/util/Seeder/Factories/CipherSeeder.cs index c751d83399..9d4c039b2c 100644 --- a/util/Seeder/Factories/CipherSeeder.cs +++ b/util/Seeder/Factories/CipherSeeder.cs @@ -22,8 +22,6 @@ namespace Bit.Seeder.Factories; /// public class CipherSeeder { - private readonly RustSdkService _sdkService; - private static readonly JsonSerializerOptions SdkJsonOptions = new() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase, @@ -36,12 +34,7 @@ public class CipherSeeder DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull }; - public CipherSeeder(RustSdkService sdkService) - { - _sdkService = sdkService; - } - - public Cipher CreateOrganizationLoginCipher( + public static Cipher CreateOrganizationLoginCipher( Guid organizationId, string orgKeyBase64, string name, @@ -67,7 +60,7 @@ public class CipherSeeder return EncryptAndTransform(cipherView, orgKeyBase64, organizationId); } - public Cipher CreateOrganizationLoginCipherWithFields( + public static Cipher CreateOrganizationLoginCipherWithFields( Guid organizationId, string orgKeyBase64, string name, @@ -98,10 +91,10 @@ public class CipherSeeder return EncryptAndTransform(cipherView, orgKeyBase64, organizationId); } - private Cipher EncryptAndTransform(CipherViewDto cipherView, string keyBase64, Guid organizationId) + private static Cipher EncryptAndTransform(CipherViewDto cipherView, string keyBase64, Guid organizationId) { var viewJson = JsonSerializer.Serialize(cipherView, SdkJsonOptions); - var encryptedJson = _sdkService.EncryptCipher(viewJson, keyBase64); + var encryptedJson = RustSdkService.EncryptCipher(viewJson, keyBase64); var encryptedDto = JsonSerializer.Deserialize(encryptedJson, SdkJsonOptions) ?? throw new InvalidOperationException("Failed to parse encrypted cipher"); diff --git a/util/Seeder/Factories/CollectionSeeder.cs b/util/Seeder/Factories/CollectionSeeder.cs index 8d86335911..231fe86b43 100644 --- a/util/Seeder/Factories/CollectionSeeder.cs +++ b/util/Seeder/Factories/CollectionSeeder.cs @@ -3,15 +3,15 @@ using Bit.RustSDK; namespace Bit.Seeder.Factories; -public class CollectionSeeder(RustSdkService sdkService) +public class CollectionSeeder { - public Collection CreateCollection(Guid organizationId, string orgKey, string name) + public static Collection CreateCollection(Guid organizationId, string orgKey, string name) { return new Collection { Id = Guid.NewGuid(), OrganizationId = organizationId, - Name = sdkService.EncryptString(name, orgKey), + Name = RustSdkService.EncryptString(name, orgKey), CreationDate = DateTime.UtcNow, RevisionDate = DateTime.UtcNow }; diff --git a/util/Seeder/Factories/FolderSeeder.cs b/util/Seeder/Factories/FolderSeeder.cs index d8674552bd..8cf7413bbc 100644 --- a/util/Seeder/Factories/FolderSeeder.cs +++ b/util/Seeder/Factories/FolderSeeder.cs @@ -8,7 +8,7 @@ namespace Bit.Seeder.Factories; /// Factory for creating Folder entities with encrypted names. /// Folders are per-user constructs encrypted with the user's symmetric key. /// -internal sealed class FolderSeeder(RustSdkService sdkService) +internal sealed class FolderSeeder { /// /// Creates a folder with an encrypted name. @@ -16,13 +16,13 @@ internal sealed class FolderSeeder(RustSdkService sdkService) /// The user who owns this folder. /// The user's symmetric key (not org key). /// The plaintext folder name to encrypt. - public Folder CreateFolder(Guid userId, string userKeyBase64, string name) + public static Folder CreateFolder(Guid userId, string userKeyBase64, string name) { return new Folder { Id = CoreHelpers.GenerateComb(), UserId = userId, - Name = sdkService.EncryptString(name, userKeyBase64) + Name = RustSdkService.EncryptString(name, userKeyBase64) }; } } diff --git a/util/Seeder/Factories/OrganizationSeeder.cs b/util/Seeder/Factories/OrganizationSeeder.cs index 0646fdd9ee..30b790c343 100644 --- a/util/Seeder/Factories/OrganizationSeeder.cs +++ b/util/Seeder/Factories/OrganizationSeeder.cs @@ -7,9 +7,6 @@ namespace Bit.Seeder.Factories; public class OrganizationSeeder { - private static readonly string _defaultPublicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmIJbGMk6eZqVE7UxhZ46Weu2jKciqOiOkSVYtGvs61rfe9AXxtLaaZEKN4d4DmkZcF6dna2eXNxZmb7U4pwlttye8ksqISe6IUAZQox7auBpjopdCEPhKRg3BD/u8ks9UxSxgWe+fpebjt6gd5hsl1/5HOObn7SeU6EEU04cp3/eH7a4OTdXxB8oN62HGV9kM/ubM1goILgjoSJDbihMK0eb7b8hPHwcA/YOgKKiu/N3FighccdSMD5Pk+HfjacsFNZQa2EsqW09IvvSZ+iL6HQeZ1vwc/6TO1J7EOfJZFQcjoEL9LVI693efYoMZSmrPEWziZ4PvwpOOGo6OObyMQIDAQAB"; - private static readonly string _defaultPrivateKey = "2.6FggyKVyaKQsfohi5yqgbg==|UU2JeafOB41L5UscGmf4kq15JGDf3Bkf67KECiehTODzbWctVLTgyDk0Qco8/6CMN6nZGXjxR2A4r5ExhmwRNsNxd77G+MprkmiJz+7w33ROZ1ouQO5XjD3wbQ3ssqNiTKId6yAUPBvuAZRixVApauTuADc8QWGixqCQcqZzmU7YSBBIPf652/AEYr4Tk64YihoE39pHiK8MRbTLdRt3EF4LSMugPAPM24vCgUv3w1TD3Fj6sDg/6oi3flOV9SJZX4vCiUXbDNEuD/p2aQrEXVbaxweFOHjTe7F4iawjXw3nG3SO8rUBHcxbhDDVx5rjYactbW5QvHWiyla6uLb6o8WHBneg2EjTEwAHOZE/rBjcqmAJb2sVp1E0Kwq8ycGmL69vmqJPC1GqVTohAQvmEkaxIPpfq24Yb9ZPrADA7iEXBKuAQ1FphFUVgJBJGJbd60sOV1Rz1T+gUwS4wCNQ4l3LG1S22+wzUVlEku5DXFnT932tatqTyWEthqPqLCt6dL1+qa94XLpeHagXAx2VGe8n8IlcADtxqS+l8xQ4heT12WO9kC316vqvg1mnsI56faup9hb3eT9ZpKyxSBGYOphlTWfV1Y/v64f5PYvTo4aL0IYHyLY/9Qi72vFmOpPeHBYgD5t3j+H2CsiU1PkYsBggOmD7xW8FDuT6HWVvwhEJqeibVPK0Lhyj6tgvlSIAvFUaSMFPlmwFNmwfj/AHUhr9KuTfsBFTZ10yy9TZVgf+EofwnrxHBaWUgdD40aHoY1VjfG33iEuajb6buxG3pYFyPNhJNzeLZisUKIDRMQpUHrsE22EyrFFran3tZGdtcyIEK4Q1F0ULYzJ6T9iY25/ZgPy3pEAAMZCtqo3s+GjX295fWIHfMcnjMgNUHPjExjWBHa+ggK9iQXkFpBVyYB1ga/+0eiIhiek3PlgtvpDrqF7TsLK+ROiBw2GJ7uaO3EEXOj2GpNBuEJ5CdodhZkwzhwMcSatgDHkUuNVu0iVbF6/MxVdOxWXKO+jCYM6PZk/vAhLYqpPzu2T2Uyz4nkDs2Tiq61ez6FoCrzdHIiyIxVTzUQH8G9FgSmtaZ7GCbqlhnurYgcMciwPzxg0hpAQT+NZw1tVEii9vFSpJJbGJqNhORKfKh/Mu1P/9LOQq7Y0P2FIR3x/eUVEQ7CGv2jVtO5ryGSmKeq/P9Fr54wTPaNiqN2K+leACUznCdUWw8kZo/AsBcrOe4OkRX6k8LC3oeJXy06DEToatxEvPYemUauhxiXRw8nfNMqc4LyJq2bbT0zCgJHoqpozPdNg6AYWcoIobgAGu7ZQGq+oE1MT3GZxotMPe/NUJiAc5YE9Thb5Yf3gyno71pyqPTVl/6IQuh4SUz7rkgwF/aVHEnr4aUYNoc0PEzd2Me0jElsA3GAneq1I/wngutOWgTViTK4Nptr5uIzMVQs9H1rOMJNorP8b02t1NDu010rSsib9GaaJJq4r4iy46laQOxWoU0ex26arYnk+jw4833WSCTVBIprTgizZ+fKjoY0xwXvI2oOvGNEUCtGFvKFORTaQrlaXZIg1toa2BBVNicyONbwnI3KIu3MgGJ2SlCVXJn8oHFppVHFCdwgN1uDzGiKAhjvr0sZTUtXin2f2CszPTbbo=|fUhbVKrr8CSKE7TZJneXpDGraj5YhRrq9ESo206S+BY="; - public static Organization CreateEnterprise(string name, string domain, int seats, string? publicKey = null, string? privateKey = null) { return new Organization @@ -43,36 +40,14 @@ public class OrganizationSeeder SyncSeats = true, Status = OrganizationStatusType.Created, MaxStorageGb = 10, - PublicKey = publicKey ?? _defaultPublicKey, - PrivateKey = privateKey ?? _defaultPrivateKey, + PublicKey = publicKey, + PrivateKey = privateKey }; } } public static class OrganizationExtensions { - /// - /// Creates an OrganizationUser with fields populated based on status. - /// For Invited status, only user.Email is used. For other statuses, user.Id is used. - /// - public static OrganizationUser CreateOrganizationUser( - this Organization organization, User user, OrganizationUserType type, OrganizationUserStatusType status) - { - var isInvited = status == OrganizationUserStatusType.Invited; - var isConfirmed = status == OrganizationUserStatusType.Confirmed || status == OrganizationUserStatusType.Revoked; - - return new OrganizationUser - { - Id = Guid.NewGuid(), - OrganizationId = organization.Id, - UserId = isInvited ? null : user.Id, - Email = isInvited ? user.Email : null, - Key = isConfirmed ? "4.rY01mZFXHOsBAg5Fq4gyXuklWfm6mQASm42DJpx05a+e2mmp+P5W6r54WU2hlREX0uoTxyP91bKKwickSPdCQQ58J45LXHdr9t2uzOYyjVzpzebFcdMw1eElR9W2DW8wEk9+mvtWvKwu7yTebzND+46y1nRMoFydi5zPVLSlJEf81qZZ4Uh1UUMLwXz+NRWfixnGXgq2wRq1bH0n3mqDhayiG4LJKgGdDjWXC8W8MMXDYx24SIJrJu9KiNEMprJE+XVF9nQVNijNAjlWBqkDpsfaWTUfeVLRLctfAqW1blsmIv4RQ91PupYJZDNc8nO9ZTF3TEVM+2KHoxzDJrLs2Q==" : null, - Type = type, - Status = status - }; - } - /// /// Creates an OrganizationUser with a dynamically provided encrypted org key. /// The encryptedOrgKey should be generated using sdkService.GenerateUserOrganizationKey(). diff --git a/util/Seeder/Factories/UserSeeder.cs b/util/Seeder/Factories/UserSeeder.cs index f355bde705..a860506e29 100644 --- a/util/Seeder/Factories/UserSeeder.cs +++ b/util/Seeder/Factories/UserSeeder.cs @@ -11,7 +11,7 @@ public struct UserData public string Email; } -public class UserSeeder(RustSdkService sdkService, IPasswordHasher passwordHasher, MangleId mangleId) +public class UserSeeder(IPasswordHasher passwordHasher, MangleId mangleId) { private string MangleEmail(string email) { @@ -21,7 +21,7 @@ public class UserSeeder(RustSdkService sdkService, IPasswordHasher public static User CreateUserWithSdkKeys( string email, - RustSdkService sdkService, IPasswordHasher passwordHasher) { - var keys = sdkService.GenerateUserKeys(email, DefaultPassword); + var keys = RustSdkService.GenerateUserKeys(email, DefaultPassword); return CreateUserFromKeys(email, keys, passwordHasher); } diff --git a/util/Seeder/Recipes/CollectionsRecipe.cs b/util/Seeder/Recipes/CollectionsRecipe.cs index e0f9057418..d587dafbb4 100644 --- a/util/Seeder/Recipes/CollectionsRecipe.cs +++ b/util/Seeder/Recipes/CollectionsRecipe.cs @@ -14,7 +14,7 @@ public class CollectionsRecipe(DatabaseContext db) /// The number of collections to add. /// The IDs of the users to create relationships with. /// The maximum number of users to create relationships with. - public List AddToOrganization(Guid organizationId, int collections, List organizationUserIds, int maxUsersWithRelationships = 1000) + public List Seed(Guid organizationId, int collections, List organizationUserIds, int maxUsersWithRelationships = 1000) { var collectionList = CreateAndSaveCollections(organizationId, collections); diff --git a/util/Seeder/Recipes/GroupsRecipe.cs b/util/Seeder/Recipes/GroupsRecipe.cs index 3c8156d921..d72730def0 100644 --- a/util/Seeder/Recipes/GroupsRecipe.cs +++ b/util/Seeder/Recipes/GroupsRecipe.cs @@ -13,7 +13,7 @@ public class GroupsRecipe(DatabaseContext db) /// The number of groups to add. /// The IDs of the users to create relationships with. /// The maximum number of users to create relationships with. - public List AddToOrganization(Guid organizationId, int groups, List organizationUserIds, int maxUsersWithRelationships = 1000) + public List Seed(Guid organizationId, int groups, List organizationUserIds, int maxUsersWithRelationships = 1000) { var groupList = CreateAndSaveGroups(organizationId, groups); diff --git a/util/Seeder/Recipes/OrganizationDomainRecipe.cs b/util/Seeder/Recipes/OrganizationDomainRecipe.cs index b62dd5115e..97b52adf21 100644 --- a/util/Seeder/Recipes/OrganizationDomainRecipe.cs +++ b/util/Seeder/Recipes/OrganizationDomainRecipe.cs @@ -5,7 +5,7 @@ namespace Bit.Seeder.Recipes; public class OrganizationDomainRecipe(DatabaseContext db) { - public void AddVerifiedDomainToOrganization(Guid organizationId, string domainName) + public void Seed(Guid organizationId, string domainName) { var domain = new OrganizationDomain { diff --git a/util/Seeder/Recipes/OrganizationWithUsersRecipe.cs b/util/Seeder/Recipes/OrganizationWithUsersRecipe.cs index 87fcc1967b..f6a21ab4ac 100644 --- a/util/Seeder/Recipes/OrganizationWithUsersRecipe.cs +++ b/util/Seeder/Recipes/OrganizationWithUsersRecipe.cs @@ -1,39 +1,66 @@ -using Bit.Core.Entities; +using AutoMapper; +using Bit.Core.Entities; using Bit.Core.Enums; using Bit.Infrastructure.EntityFramework.Repositories; +using Bit.RustSDK; using Bit.Seeder.Factories; using LinqToDB.EntityFrameworkCore; +using Microsoft.AspNetCore.Identity; +using EfOrganization = Bit.Infrastructure.EntityFramework.AdminConsole.Models.Organization; +using EfOrganizationUser = Bit.Infrastructure.EntityFramework.Models.OrganizationUser; +using EfUser = Bit.Infrastructure.EntityFramework.Models.User; namespace Bit.Seeder.Recipes; -public class OrganizationWithUsersRecipe(DatabaseContext db) +public class OrganizationWithUsersRecipe(DatabaseContext db, IMapper mapper, IPasswordHasher passwordHasher) { public Guid Seed(string name, string domain, int users, OrganizationUserStatusType usersStatus = OrganizationUserStatusType.Confirmed) { var seats = Math.Max(users + 1, 1000); - var organization = OrganizationSeeder.CreateEnterprise(name, domain, seats); - var ownerUser = UserSeeder.CreateUserNoMangle($"owner@{domain}"); - var ownerOrgUser = organization.CreateOrganizationUser(ownerUser, OrganizationUserType.Owner, OrganizationUserStatusType.Confirmed); + + // Generate organization keys + var orgKeys = RustSdkService.GenerateOrganizationKeys(); + var organization = OrganizationSeeder.CreateEnterprise( + name, domain, seats, orgKeys.PublicKey, orgKeys.PrivateKey); + + // Create owner with SDK-generated keys + var ownerUser = UserSeeder.CreateUserWithSdkKeys($"owner@{domain}", passwordHasher); + var ownerOrgKey = RustSdkService.GenerateUserOrganizationKey(ownerUser.PublicKey!, orgKeys.Key); + var ownerOrgUser = organization.CreateOrganizationUserWithKey( + ownerUser, OrganizationUserType.Owner, OrganizationUserStatusType.Confirmed, ownerOrgKey); var additionalUsers = new List(); var additionalOrgUsers = new List(); for (var i = 0; i < users; i++) { - var additionalUser = UserSeeder.CreateUserNoMangle($"user{i}@{domain}"); + var additionalUser = UserSeeder.CreateUserWithSdkKeys($"user{i}@{domain}", passwordHasher); additionalUsers.Add(additionalUser); - additionalOrgUsers.Add(organization.CreateOrganizationUser(additionalUser, OrganizationUserType.User, usersStatus)); + + // Generate org key for confirmed/revoked users + var shouldHaveKey = usersStatus == OrganizationUserStatusType.Confirmed + || usersStatus == OrganizationUserStatusType.Revoked; + var userOrgKey = shouldHaveKey + ? RustSdkService.GenerateUserOrganizationKey(additionalUser.PublicKey!, orgKeys.Key) + : null; + + additionalOrgUsers.Add(organization.CreateOrganizationUserWithKey( + additionalUser, OrganizationUserType.User, usersStatus, userOrgKey)); } - db.Add(organization); - db.Add(ownerUser); - db.Add(ownerOrgUser); + // Map Core entities to EF entities before adding to DbContext + db.Add(mapper.Map(organization)); + db.Add(mapper.Map(ownerUser)); + db.Add(mapper.Map(ownerOrgUser)); + + // Map and BulkCopy additional users + var efAdditionalUsers = additionalUsers.Select(u => mapper.Map(u)).ToList(); + var efAdditionalOrgUsers = additionalOrgUsers.Select(ou => mapper.Map(ou)).ToList(); + + db.BulkCopy(efAdditionalUsers); + db.BulkCopy(efAdditionalOrgUsers); db.SaveChanges(); - // Use LinqToDB's BulkCopy for significant better performance - db.BulkCopy(additionalUsers); - db.BulkCopy(additionalOrgUsers); - return organization.Id; } } diff --git a/util/Seeder/Recipes/OrganizationWithVaultRecipe.cs b/util/Seeder/Recipes/OrganizationWithVaultRecipe.cs index 44c86f49f0..6b729273f1 100644 --- a/util/Seeder/Recipes/OrganizationWithVaultRecipe.cs +++ b/util/Seeder/Recipes/OrganizationWithVaultRecipe.cs @@ -27,12 +27,8 @@ namespace Bit.Seeder.Recipes; public class OrganizationWithVaultRecipe( DatabaseContext db, IMapper mapper, - RustSdkService sdkService, IPasswordHasher passwordHasher) { - private readonly CollectionSeeder _collectionSeeder = new(sdkService); - private readonly CipherSeeder _cipherSeeder = new(sdkService); - private readonly FolderSeeder _folderSeeder = new(sdkService); /// /// Tracks a user with their symmetric key for folder encryption. @@ -47,15 +43,15 @@ public class OrganizationWithVaultRecipe( public Guid Seed(OrganizationVaultOptions options) { var seats = Math.Max(options.Users + 1, 1000); - var orgKeys = sdkService.GenerateOrganizationKeys(); + var orgKeys = RustSdkService.GenerateOrganizationKeys(); // Create organization via factory var organization = OrganizationSeeder.CreateEnterprise( options.Name, options.Domain, seats, orgKeys.PublicKey, orgKeys.PrivateKey); // Create owner user via factory - var ownerUser = UserSeeder.CreateUserWithSdkKeys($"owner@{options.Domain}", sdkService, passwordHasher); - var ownerOrgKey = sdkService.GenerateUserOrganizationKey(ownerUser.PublicKey!, orgKeys.Key); + var ownerUser = UserSeeder.CreateUserWithSdkKeys($"owner@{options.Domain}", passwordHasher); + var ownerOrgKey = RustSdkService.GenerateUserOrganizationKey(ownerUser.PublicKey!, orgKeys.Key); var ownerOrgUser = organization.CreateOrganizationUserWithKey( ownerUser, OrganizationUserType.Owner, OrganizationUserStatusType.Confirmed, ownerOrgKey); @@ -67,7 +63,7 @@ public class OrganizationWithVaultRecipe( for (var i = 0; i < options.Users; i++) { var email = $"user{i}@{options.Domain}"; - var userKeys = sdkService.GenerateUserKeys(email, UserSeeder.DefaultPassword); + var userKeys = RustSdkService.GenerateUserKeys(email, UserSeeder.DefaultPassword); var memberUser = UserSeeder.CreateUserFromKeys(email, userKeys, passwordHasher); memberUsersWithKeys.Add(new UserWithKey(memberUser, userKeys.Key)); @@ -77,7 +73,7 @@ public class OrganizationWithVaultRecipe( var memberOrgKey = (status == OrganizationUserStatusType.Confirmed || status == OrganizationUserStatusType.Revoked) - ? sdkService.GenerateUserOrganizationKey(memberUser.PublicKey!, orgKeys.Key) + ? RustSdkService.GenerateUserOrganizationKey(memberUser.PublicKey!, orgKeys.Key) : null; memberOrgUsers.Add(organization.CreateOrganizationUserWithKey( @@ -124,12 +120,12 @@ public class OrganizationWithVaultRecipe( { var structure = OrgStructures.GetStructure(structureModel.Value); collections = structure.Units - .Select(unit => _collectionSeeder.CreateCollection(organizationId, orgKeyBase64, unit.Name)) + .Select(unit => CollectionSeeder.CreateCollection(organizationId, orgKeyBase64, unit.Name)) .ToList(); } else { - collections = [_collectionSeeder.CreateCollection(organizationId, orgKeyBase64, "Default Collection")]; + collections = [CollectionSeeder.CreateCollection(organizationId, orgKeyBase64, "Default Collection")]; } db.BulkCopy(collections); @@ -191,7 +187,7 @@ public class OrganizationWithVaultRecipe( .Select(i => { var company = companies[i % companies.Length]; - return _cipherSeeder.CreateOrganizationLoginCipher( + return CipherSeeder.CreateOrganizationLoginCipher( organizationId, orgKeyBase64, name: $"{company.Name} ({company.Category})", @@ -285,7 +281,7 @@ public class OrganizationWithVaultRecipe( { var folderCount = GetFolderCountForUser(userIndex, usersWithKeys.Count, random); return Enumerable.Range(0, folderCount) - .Select(folderIndex => _folderSeeder.CreateFolder( + .Select(folderIndex => FolderSeeder.CreateFolder( uwk.User.Id, uwk.SymmetricKey, folderNameGenerator.GetFolderName(userIndex * 15 + folderIndex))); diff --git a/util/SeederApi/Startup.cs b/util/SeederApi/Startup.cs index 420078f509..5caf0208e3 100644 --- a/util/SeederApi/Startup.cs +++ b/util/SeederApi/Startup.cs @@ -37,7 +37,6 @@ public class Startup services.AddScoped, PasswordHasher>(); - services.AddSingleton(); services.AddScoped(); services.AddSeederApiServices();