using ZB.MOM.WW.Configuration;
using ZB.MOM.WW.OtOpcUa.Core.Authorization;
namespace ZB.MOM.WW.OtOpcUa.Host.Configuration;
///
/// Fail-fast startup validator for (R03:2.3). The pepper used to be
/// checked only when the first key was verified — ApiKeySecret.Verify throws on an empty one —
/// so a site node deployed without Security__ApiKeys__Pepper booted green, passed health,
/// applied deployments and denied every machine client with the same opaque "Invalid API key" until
/// someone read the log; a central node with a wrong pepper minted keys that could verify nowhere.
/// Every other security section already fails host start on a bad value; this one now does too.
///
///
/// Registered for hasDriver || hasAdmin: a driver node needs the pepper to VERIFY keys, an admin
/// node to MINT them. The minimum length is a floor against a placeholder ("x") passing as
/// configured, not a strength claim — the pepper is a server-side secret, not a password.
///
public sealed class ApiKeyOptionsValidator : OptionsValidatorBase
{
/// The shortest pepper accepted (characters, after trimming).
public const int MinPepperLength = 16;
///
protected override void Validate(ValidationBuilder builder, ApiKeyOptions options)
{
var pepper = options.Pepper?.Trim() ?? string.Empty;
builder.RequireThat(pepper.Length > 0,
$"{ApiKeyOptions.SectionName}:Pepper is required on any node with the driver or admin role — " +
"supply it via Security__ApiKeys__Pepper or a ${secret:} reference. An empty pepper would reject " +
"every API key (driver) or mint keys that can never verify (admin).");
builder.RequireThat(pepper.Length == 0 || pepper.Length >= MinPepperLength,
$"{ApiKeyOptions.SectionName}:Pepper must be at least {MinPepperLength} characters.");
builder.RequireThat(!string.IsNullOrWhiteSpace(options.Username),
$"{ApiKeyOptions.SectionName}:Username must not be blank.");
builder.RequireThat(options.StoreTimeoutMs >= 0,
$"{ApiKeyOptions.SectionName}:StoreTimeoutMs must be >= 0 (0 disables the deadline).");
builder.RequireThat(options.StoreCacheSeconds >= 0,
$"{ApiKeyOptions.SectionName}:StoreCacheSeconds must be >= 0 (0 disables the cache).");
}
}