1
0
mirror of https://github.com/bitwarden/server synced 2026-02-12 14:33:49 +00:00
Files
server/util/Seeder/Data/GeneratorContext.cs

88 lines
2.7 KiB
C#

using System.Security.Cryptography;
using System.Text;
using Bit.Seeder.Data.Enums;
using Bit.Seeder.Data.Generators;
using Bit.Seeder.Options;
namespace Bit.Seeder.Data;
/// <summary>
/// Centralized context for all data generators in a seeding operation.
/// Lazy-initializes generators on first access to avoid creating unused instances.
/// </summary>
/// <remarks>
/// Adding a new generator:
/// 1. Add private nullable field
/// 2. Add public property with lazy initialization
/// 3. Use in Recipe via _ctx.NewGenerator.Method()
/// </remarks>
internal sealed class GeneratorContext
{
private readonly int _seed;
private readonly GeographicRegion _region;
private readonly OrganizationVaultOptions _options;
private GeneratorContext(int seed, GeographicRegion region, OrganizationVaultOptions options)
{
_seed = seed;
_region = region;
_options = options;
}
/// <summary>
/// Creates a GeneratorContext from vault options, deriving seed from domain if not specified.
/// </summary>
public static GeneratorContext FromOptions(OrganizationVaultOptions options)
{
var seed = options.Seed ?? DeriveStableSeed(options.Domain);
var region = options.Region ?? GeographicRegion.Global;
return new GeneratorContext(seed, region, options);
}
/// <summary>
/// Derives a stable 32-bit seed from a domain string using SHA256.
/// Same input always produces same output for deterministic generation.
/// </summary>
private static int DeriveStableSeed(string domain)
{
var bytes = SHA256.HashData(Encoding.UTF8.GetBytes(domain));
return BitConverter.ToInt32(bytes, 0);
}
/// <summary>
/// The seed used for deterministic generation. Exposed for distribution calculations.
/// </summary>
public int Seed => _seed;
/// <summary>
/// Total cipher count from options. Used for distribution calculations.
/// </summary>
public int CipherCount => _options.Ciphers;
private CipherUsernameGenerator? _username;
public CipherUsernameGenerator Username => _username ??= new(
_seed,
_options.UsernameDistribution,
_region,
_options.UsernamePattern);
private FolderNameGenerator? _folder;
public FolderNameGenerator Folder => _folder ??= new(_seed);
private CardDataGenerator? _card;
public CardDataGenerator Card => _card ??= new(_seed, _region);
private IdentityDataGenerator? _identity;
public IdentityDataGenerator Identity => _identity ??= new(_seed, _region);
private SecureNoteDataGenerator? _secureNote;
public SecureNoteDataGenerator SecureNote => _secureNote ??= new(_seed);
}