feat(register): [PM-27084] Account Register Uses New Data Types - Initial changes

This commit is contained in:
Patrick Pimentel 2025-12-09 16:13:46 -05:00
parent 6d5d7e58a6
commit 6c7daa6343
No known key found for this signature in database
GPG Key ID: 4B27FC74C6422186
3 changed files with 59 additions and 13 deletions

View File

@ -1,6 +1,7 @@
#nullable enable
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.KeyManagement.Models.Data;
using Bit.Core.Utilities;
namespace Bit.Core.Auth.Models.Api.Request.Accounts;
@ -21,18 +22,25 @@ public class RegisterFinishRequestModel : IValidatableObject
public required string Email { get; set; }
public string? EmailVerificationToken { get; set; }
public MasterPasswordAuthenticationData? MasterPasswordAuthenticationData { get; set; }
public MasterPasswordUnlockData? MasterPasswordUnlockData { get; set; }
// PM-28143 - Made to be optional as migrating to MasterPasswordUnlockData
[StringLength(1000)]
public required string MasterPasswordHash { get; set; }
public required string? MasterPasswordHash { get; set; }
[StringLength(50)]
public string? MasterPasswordHint { get; set; }
public required string UserSymmetricKey { get; set; }
// PM-28143 - Remove line below (made optional during migration to MasterPasswordUnlockData
public string? UserSymmetricKey { get; set; }
public required KeysRequestModel UserAsymmetricKeys { get; set; }
public required KdfType Kdf { get; set; }
public required int KdfIterations { get; set; }
// PM-28143 - Remove line below (made optional during migration to MasterPasswordUnlockData
public KdfType? Kdf { get; set; }
// PM-28143 - Remove line below (made optional during migration to MasterPasswordUnlockData
public int? KdfIterations { get; set; }
public int? KdfMemory { get; set; }
public int? KdfParallelism { get; set; }
@ -54,11 +62,13 @@ public class RegisterFinishRequestModel : IValidatableObject
{
Email = Email,
MasterPasswordHint = MasterPasswordHint,
Kdf = Kdf,
KdfIterations = KdfIterations,
KdfMemory = KdfMemory,
KdfParallelism = KdfParallelism,
Key = UserSymmetricKey,
Kdf = MasterPasswordUnlockData?.Kdf.KdfType ?? Kdf ?? throw new Exception($"{nameof(Kdf)} is required"),
KdfIterations = MasterPasswordUnlockData?.Kdf.Iterations ?? KdfIterations ?? throw new Exception($"{nameof(KdfIterations)} is required"),
KdfMemory = MasterPasswordUnlockData?.Kdf.Memory ?? KdfMemory,
KdfParallelism = MasterPasswordUnlockData?.Kdf.Parallelism ?? KdfParallelism,
// PM-28827 To be added when MasterPasswordSalt is added to the user column
// MasterPasswordSalt = MasterPasswordUnlockData?.Salt ?? Email.ToLower().Trim(),
Key = MasterPasswordUnlockData?.MasterKeyWrappedUserKey ?? UserSymmetricKey,
};
UserAsymmetricKeys.ToUser(user);
@ -95,6 +105,15 @@ public class RegisterFinishRequestModel : IValidatableObject
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
return KdfSettingsValidator.Validate(Kdf, KdfIterations, KdfMemory, KdfParallelism);
var kdf = MasterPasswordUnlockData?.Kdf.KdfType ?? Kdf ?? throw new Exception($"{nameof(Kdf)} not found on RequestModel");
var kdfIterations = MasterPasswordUnlockData?.Kdf.Iterations ?? KdfIterations ?? throw new Exception($"{nameof(KdfIterations)} not found on RequestModel");
var kdfMemory = MasterPasswordUnlockData?.Kdf.Memory ?? KdfMemory;
var kdfParallelism = MasterPasswordUnlockData?.Kdf.Parallelism ?? KdfParallelism;
// PM-28143 - Remove line below in favor of using the unlock data.
return KdfSettingsValidator.Validate(kdf, kdfIterations, kdfMemory, kdfParallelism);
// PM-28143 - Uncomment
// return KdfSettingsValidator.Validate(MasterPasswordUnlockData);
}
}

View File

@ -7,8 +7,6 @@ using Bit.Core.KeyManagement.Models.Data;
using Bit.Core.Utilities;
using Microsoft.AspNetCore.Identity;
#nullable enable
namespace Bit.Core.Entities;
public class User : ITableObject<Guid>, IStorableSubscriber, IRevisable, ITwoFactorProvidersUser
@ -51,7 +49,7 @@ public class User : ITableObject<Guid>, IStorableSubscriber, IRevisable, ITwoFac
public string? Key { get; set; }
/// <summary>
/// The raw public key, without a signature from the user's signature key.
/// </summary>
/// </summary>
public string? PublicKey { get; set; }
/// <summary>
/// User key wrapped private key.
@ -102,6 +100,8 @@ public class User : ITableObject<Guid>, IStorableSubscriber, IRevisable, ITwoFac
public DateTime? LastKeyRotationDate { get; set; }
public DateTime? LastEmailChangeDate { get; set; }
public bool VerifyDevices { get; set; } = true;
// PM-28827 Uncomment below line.
// public string? MasterPasswordSalt { get; set; }
public string GetMasterPasswordSalt()
{

View File

@ -36,6 +36,33 @@ public static class KdfSettingsValidator
}
}
public static IEnumerable<ValidationResult> Validate(MasterPasswordUnlockData masterPasswordUnlockData)
{
switch (masterPasswordUnlockData.Kdf.KdfType)
{
case KdfType.PBKDF2_SHA256:
if (!AuthConstants.PBKDF2_ITERATIONS.InsideRange(masterPasswordUnlockData.Kdf.Iterations))
{
yield return new ValidationResult($"KDF iterations must be between {AuthConstants.PBKDF2_ITERATIONS.Min} and {AuthConstants.PBKDF2_ITERATIONS.Max}.");
}
break;
case KdfType.Argon2id:
if (!AuthConstants.ARGON2_ITERATIONS.InsideRange(masterPasswordUnlockData.Kdf.Iterations))
{
yield return new ValidationResult($"Argon2 iterations must be between {AuthConstants.ARGON2_ITERATIONS.Min} and {AuthConstants.ARGON2_ITERATIONS.Max}.");
}
else if (!masterPasswordUnlockData.Kdf.Memory.HasValue || !AuthConstants.ARGON2_MEMORY.InsideRange(masterPasswordUnlockData.Kdf.Memory.Value))
{
yield return new ValidationResult($"Argon2 memory must be between {AuthConstants.ARGON2_MEMORY.Min}mb and {AuthConstants.ARGON2_MEMORY.Max}mb.");
}
else if (!masterPasswordUnlockData.Kdf.Parallelism.HasValue || !AuthConstants.ARGON2_PARALLELISM.InsideRange(masterPasswordUnlockData.Kdf.Parallelism.Value))
{
yield return new ValidationResult($"Argon2 parallelism must be between {AuthConstants.ARGON2_PARALLELISM.Min} and {AuthConstants.ARGON2_PARALLELISM.Max}.");
}
break;
}
}
public static IEnumerable<ValidationResult> Validate(KdfSettings settings)
{
return Validate(settings.KdfType, settings.Iterations, settings.Memory, settings.Parallelism);