1
0
mirror of https://github.com/bitwarden/server synced 2026-02-28 10:23:24 +00:00

Scene to create a folder for a user (#7099)

This commit is contained in:
Matt Gibson
2026-02-27 08:35:42 +00:00
committed by GitHub
parent 415805679d
commit 9ca1874723
7 changed files with 54 additions and 8 deletions

View File

@@ -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<User> passwordHasher,
IManglerService manglerService,
@@ -45,6 +45,6 @@ internal static class UserSeeder
user.MasterPassword = passwordHasher.HashPassword(user, keys.MasterPasswordHash);
return user;
return (user, keys);
}
}

View File

@@ -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<OrganizationUser>();
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

View File

@@ -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<SceneResult<SingleUserSceneResult>> 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());
}

View File

@@ -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<UserFolderScene.Request, UserFolderScene.Result>
{
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<SceneResult<Result>> 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>(
result: new Result
{
FolderId = folder.Id,
},
mangleMap: manglerService.GetMangleMap());
}
}

View File

@@ -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());

View File

@@ -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(

View File

@@ -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);