using System.Text.RegularExpressions; using FluentValidation; namespace TeleWave.Application.Broadcast.Bumpers; public sealed partial class UpdateBumperTemplateCommandValidator : AbstractValidator { public UpdateBumperTemplateCommandValidator() { RuleFor(x => x.Name).NotEmpty().MaximumLength(64); // Цвета уходят в строку ffmpeg-фильтра без экранирования — допускаем только безопасный формат // (0xRRGGBB[AA], #RRGGBB[AA] или имя цвета), чтобы исключить инъекцию синтаксиса фильтра. RuleFor(x => x.BackgroundColor).Must(BeSafeColor).WithMessage(ColorMessage); RuleFor(x => x.BackgroundColor2).Must(BeSafeColor).WithMessage(ColorMessage); RuleFor(x => x.AccentColor).Must(BeSafeColor).WithMessage(ColorMessage); RuleFor(x => x.TextColor).Must(BeSafeColor).WithMessage(ColorMessage); } private const string ColorMessage = "Цвет должен быть в формате 0xRRGGBB, #RRGGBB или именем (например white)."; private static bool BeSafeColor(string? value) => !string.IsNullOrWhiteSpace(value) && ColorRegex().IsMatch(value); [GeneratedRegex(@"^((0x|#)?[0-9A-Fa-f]{6}([0-9A-Fa-f]{2})?|[A-Za-z]{2,20}(@[0-9]?\.?[0-9]+)?)$")] private static partial Regex ColorRegex(); }