feat(dir): validate URLs for new FilterLists

This commit is contained in:
Collin M. Barrett 2021-12-06 09:54:48 -06:00
parent 48bf2a87cd
commit 53985dac58
4 changed files with 65 additions and 6 deletions

View file

@ -182,11 +182,30 @@ public record FilterListViewUrl
internal class Validator : AbstractValidator<Command>
{
public Validator()
public Validator(IValidator<Uri?> urlValidator)
{
RuleFor(c => c.LicenseId)
.GreaterThan(0)
.When(c => c.LicenseId != null);
RuleForEach(c => c.ViewUrls.Select(u => u.Url))
.SetValidator(urlValidator)
.OverridePropertyName(nameof(Command.ViewUrls));
RuleFor(c => c.HomeUrl)
.SetValidator(urlValidator);
RuleFor(c => c.OnionUrl)
.SetValidator(urlValidator);
RuleFor(c => c.PolicyUrl)
.SetValidator(urlValidator);
RuleFor(c => c.SubmissionUrl)
.SetValidator(urlValidator);
RuleFor(c => c.IssuesUrl)
.SetValidator(urlValidator);
RuleFor(c => c.ForumUrl)
.SetValidator(urlValidator);
RuleFor(c => c.ChatUrl)
.SetValidator(urlValidator);
RuleFor(c => c.DonateUrl)
.SetValidator(urlValidator);
}
}

View file

@ -1,4 +1,5 @@
using FilterLists.Directory.Infrastructure;
using FilterLists.Directory.Application.Validators;
using FilterLists.Directory.Infrastructure;
using FluentValidation;
using MediatR;
using Microsoft.AspNetCore.Builder;
@ -17,11 +18,12 @@ public static IHostBuilder ConfigureApplication(this IHostBuilder hostBuilder)
public static void AddApplication(this IServiceCollection services, IConfiguration configuration)
{
services.AddMediatR(typeof(ConfigurationExtensions).Assembly);
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidatorPipelineBehavior<,>));
services.AddInfrastructure(configuration);
services.AddHttpClient();
services.AddValidatorsFromAssembly(typeof(ConfigurationExtensions).Assembly, includeInternalTypes: true);
services.AddAutoMapper(typeof(ConfigurationExtensions).Assembly);
services.AddInfrastructure(configuration);
services.AddMediatR(typeof(ConfigurationExtensions).Assembly);
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidatorPipelineBehavior<,>));
}
public static void UseApplication(this IApplicationBuilder app)

View file

@ -0,0 +1,38 @@
using FluentValidation;
namespace FilterLists.Directory.Application.Validators;
internal class UriValidator : AbstractValidator<Uri?>
{
public UriValidator(IHttpClientFactory httpClientFactory)
{
RuleFor(u => u)
.Cascade(CascadeMode.Stop)
.Must(u => Uri.TryCreate(u?.OriginalString, UriKind.Absolute, out _))
.WithMessage(u => $"Malformed absolute URL {u?.OriginalString}.")
.CustomAsync(
async (u, context, token) =>
{
var response = default(HttpResponseMessage?);
try
{
response = await httpClientFactory.CreateClient()
.GetAsync(u, HttpCompletionOption.ResponseHeadersRead, token);
}
catch (HttpRequestException ex)
{
context.AddFailure($"Error accessing URL {u?.OriginalString}. {ex.Message}");
}
catch (InvalidOperationException ex)
{
context.AddFailure($"Error accessing URL {u?.OriginalString}. {ex.Message}");
}
if (response?.IsSuccessStatusCode != true)
{
context.AddFailure($"Error accessing URL {u?.OriginalString}. {response?.StatusCode}");
}
})
.When(u => u is not null);
}
}

View file

@ -1,7 +1,7 @@
using FluentValidation;
using MediatR;
namespace FilterLists.Directory.Application;
namespace FilterLists.Directory.Application.Validators;
internal class ValidatorPipelineBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
where TRequest : notnull