diff --git a/util/Seeder/Factories/UserSeeder.cs b/util/Seeder/Factories/UserSeeder.cs index 6550e4c3df..fa3779cd89 100644 --- a/util/Seeder/Factories/UserSeeder.cs +++ b/util/Seeder/Factories/UserSeeder.cs @@ -11,7 +11,7 @@ internal static class UserSeeder { internal const string DefaultPassword = "asdfasdfasdf"; - internal static User Create( + internal static (User user, UserKeys keys) Create( string email, IPasswordHasher passwordHasher, IManglerService manglerService, @@ -45,6 +45,6 @@ internal static class UserSeeder user.MasterPassword = passwordHasher.HashPassword(user, keys.MasterPasswordHash); - return user; + return (user, keys); } } diff --git a/util/Seeder/Recipes/OrganizationWithUsersRecipe.cs b/util/Seeder/Recipes/OrganizationWithUsersRecipe.cs index 00a1206b3b..440746a1ed 100644 --- a/util/Seeder/Recipes/OrganizationWithUsersRecipe.cs +++ b/util/Seeder/Recipes/OrganizationWithUsersRecipe.cs @@ -29,7 +29,7 @@ public class OrganizationWithUsersRecipe( name, domain, seats, manglerService, orgKeys.PublicKey, orgKeys.PrivateKey); // Create owner with SDK-generated keys - var ownerUser = UserSeeder.Create($"owner@{domain}", passwordHasher, manglerService); + var (ownerUser, _) = UserSeeder.Create($"owner@{domain}", passwordHasher, manglerService); var ownerOrgKey = RustSdkService.GenerateUserOrganizationKey(ownerUser.PublicKey!, orgKeys.Key); var ownerOrgUser = organization.CreateOrganizationUserWithKey( ownerUser, OrganizationUserType.Owner, OrganizationUserStatusType.Confirmed, ownerOrgKey); @@ -38,7 +38,7 @@ public class OrganizationWithUsersRecipe( var additionalOrgUsers = new List(); for (var i = 0; i < users; i++) { - var additionalUser = UserSeeder.Create($"user{i}@{domain}", passwordHasher, manglerService); + var (additionalUser, _) = UserSeeder.Create($"user{i}@{domain}", passwordHasher, manglerService); additionalUsers.Add(additionalUser); // Generate org key for confirmed/revoked users diff --git a/util/Seeder/Scenes/SingleUserScene.cs b/util/Seeder/Scenes/SingleUserScene.cs index f7167b2bf9..4c0447b80e 100644 --- a/util/Seeder/Scenes/SingleUserScene.cs +++ b/util/Seeder/Scenes/SingleUserScene.cs @@ -13,6 +13,7 @@ public struct SingleUserSceneResult public string Kdf { get; init; } public int KdfIterations { get; init; } public string Key { get; init; } + public string DecryptedKeyB64 { get; init; } public string PublicKey { get; init; } public string PrivateKey { get; init; } public string ApiKey { get; init; } @@ -39,7 +40,7 @@ public class SingleUserScene( public async Task> SeedAsync(Request request) { // Pass service to factory - factory will call Mangle() - var user = UserSeeder.Create( + var (user, keys) = UserSeeder.Create( request.Email, passwordHasher, manglerService, @@ -59,6 +60,7 @@ public class SingleUserScene( PublicKey = user.PublicKey!, PrivateKey = user.PrivateKey!, ApiKey = user.ApiKey!, + DecryptedKeyB64 = keys.Key }, mangleMap: manglerService.GetMangleMap()); } diff --git a/util/Seeder/Scenes/UserFolderScene.cs b/util/Seeder/Scenes/UserFolderScene.cs new file mode 100644 index 0000000000..e821dc8e22 --- /dev/null +++ b/util/Seeder/Scenes/UserFolderScene.cs @@ -0,0 +1,44 @@ +using System.ComponentModel.DataAnnotations; +using Bit.Core.Repositories; +using Bit.Core.Vault.Repositories; +using Bit.Seeder.Factories; +using Bit.Seeder.Services; + +namespace Bit.Seeder.Scenes; + +public class UserFolderScene(IUserRepository userRepository, IFolderRepository folderRepository, IManglerService manglerService) : IScene +{ + public class Request + { + [Required] + public required Guid UserId { get; set; } + [Required] + public required string UserKeyB64 { get; set; } + [Required] + public required string FolderName { get; set; } + } + + public class Result + { + public Guid FolderId { get; init; } + } + + public async Task> SeedAsync(Request request) + { + var user = await userRepository.GetByIdAsync(request.UserId); + if (user == null) + { + throw new Exception($"User with ID {request.UserId} not found."); + } + + var folder = FolderSeeder.Create(request.UserId, request.UserKeyB64, request.FolderName); + await folderRepository.CreateAsync(folder); + + return new SceneResult( + result: new Result + { + FolderId = folder.Id, + }, + mangleMap: manglerService.GetMangleMap()); + } +} diff --git a/util/Seeder/Steps/CreateOwnerStep.cs b/util/Seeder/Steps/CreateOwnerStep.cs index 856fc627f0..c63e58f206 100644 --- a/util/Seeder/Steps/CreateOwnerStep.cs +++ b/util/Seeder/Steps/CreateOwnerStep.cs @@ -16,7 +16,7 @@ internal sealed class CreateOwnerStep : IStep var password = context.GetPassword(); var ownerEmail = context.GetMangler().Mangle($"owner@{context.RequireDomain()}"); var userKeys = RustSdkService.GenerateUserKeys(ownerEmail, password); - var owner = UserSeeder.Create(ownerEmail, context.GetPasswordHasher(), context.GetMangler(), keys: userKeys, password: password); + var (owner, _) = UserSeeder.Create(ownerEmail, context.GetPasswordHasher(), context.GetMangler(), keys: userKeys, password: password); var ownerOrgKey = RustSdkService.GenerateUserOrganizationKey(owner.PublicKey!, context.RequireOrgKey()); diff --git a/util/Seeder/Steps/CreateRosterStep.cs b/util/Seeder/Steps/CreateRosterStep.cs index 3cf63dbdb9..37a5128ecd 100644 --- a/util/Seeder/Steps/CreateRosterStep.cs +++ b/util/Seeder/Steps/CreateRosterStep.cs @@ -39,7 +39,7 @@ internal sealed class CreateRosterStep(string fixtureName) : IStep var mangledEmail = context.GetMangler().Mangle(email); var password = context.GetPassword(); var userKeys = RustSdkService.GenerateUserKeys(mangledEmail, password); - var user = UserSeeder.Create(mangledEmail, context.GetPasswordHasher(), context.GetMangler(), keys: userKeys, password: password); + var (user, _) = UserSeeder.Create(mangledEmail, context.GetPasswordHasher(), context.GetMangler(), keys: userKeys, password: password); var userOrgKey = RustSdkService.GenerateUserOrganizationKey(user.PublicKey!, orgKey); var orgUserType = ParseRole(rosterUser.Role); var orgUser = org.CreateOrganizationUserWithKey( diff --git a/util/Seeder/Steps/CreateUsersStep.cs b/util/Seeder/Steps/CreateUsersStep.cs index 4d20e044a1..5c2ff7764e 100644 --- a/util/Seeder/Steps/CreateUsersStep.cs +++ b/util/Seeder/Steps/CreateUsersStep.cs @@ -35,7 +35,7 @@ internal sealed class CreateUsersStep(int count, bool realisticStatusMix = false var email = $"user{i}@{domain}"; var mangledEmail = context.GetMangler().Mangle(email); var userKeys = RustSdkService.GenerateUserKeys(mangledEmail, password); - var user = UserSeeder.Create(mangledEmail, context.GetPasswordHasher(), context.GetMangler(), keys: userKeys, password: password); + var (user, _) = UserSeeder.Create(mangledEmail, context.GetPasswordHasher(), context.GetMangler(), keys: userKeys, password: password); var status = statusDistribution.Select(i, count);