Add UK education verification and security fixes

Features:
- Add UK institution recognition (170+ universities)
- Add diploma mill detection (100+ blacklisted institutions)
- Add education verification service with date plausibility checks
- Add local file storage option (no Azure required)
- Add default admin user seeding on startup
- Enhance Serilog logging with file output

Security fixes:
- Fix path traversal vulnerability in LocalFileStorageService
- Fix open redirect in login endpoint (use LocalRedirect)
- Fix password validation message (12 chars, not 6)
- Fix login to use HTTP POST endpoint (avoid Blazor cookie issues)

Code improvements:
- Add CancellationToken propagation to CV parser
- Add shared helpers (JsonDefaults, DateHelpers, ScoreThresholds)
- Add IUserContextService for user ID extraction
- Parallelized company verification in ProcessCVCheckJob
- Add 28 unit tests for education verification

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-20 16:45:43 +01:00
parent c6d52a38b2
commit f1ccd217d8
35 changed files with 1791 additions and 415 deletions

View File

@@ -1,4 +1,3 @@
using Azure.Storage.Blobs;
using Hangfire;
using Hangfire.SqlServer;
using Microsoft.EntityFrameworkCore;
@@ -59,6 +58,9 @@ public static class DependencyInjection
services.Configure<AzureBlobSettings>(
configuration.GetSection(AzureBlobSettings.SectionName));
services.Configure<LocalStorageSettings>(
configuration.GetSection(LocalStorageSettings.SectionName));
// Configure HttpClient for CompaniesHouseClient with retry policy
services.AddHttpClient<CompaniesHouseClient>((serviceProvider, client) =>
{
@@ -73,22 +75,24 @@ public static class DependencyInjection
})
.AddPolicyHandler(GetRetryPolicy());
// Configure BlobServiceClient
var azureBlobConnectionString = configuration
.GetSection(AzureBlobSettings.SectionName)
.GetValue<string>("ConnectionString");
if (!string.IsNullOrWhiteSpace(azureBlobConnectionString))
{
services.AddSingleton(_ => new BlobServiceClient(azureBlobConnectionString));
}
// Register services
services.AddScoped<ICVParserService, CVParserService>();
services.AddScoped<ICompanyVerifierService, CompanyVerifierService>();
services.AddScoped<IEducationVerifierService, EducationVerifierService>();
services.AddScoped<ITimelineAnalyserService, TimelineAnalyserService>();
services.AddScoped<IFileStorageService, FileStorageService>();
services.AddScoped<ICVCheckService, CVCheckService>();
services.AddScoped<IUserContextService, UserContextService>();
// Register file storage - use local storage if configured, otherwise Azure
var useLocalStorage = configuration.GetValue<bool>("UseLocalStorage");
if (useLocalStorage)
{
services.AddScoped<IFileStorageService, LocalFileStorageService>();
}
else
{
services.AddScoped<IFileStorageService, FileStorageService>();
}
// Register Hangfire jobs
services.AddTransient<ProcessCVCheckJob>();