using System.Net; using Microsoft.AspNetCore.HttpOverrides; using Tiku.Api.Options; using Tiku.Application.Tenancy; namespace Tiku.Api.Configuration; internal static class NetworkConfigurationExtensions { internal static IServiceCollection AddNetworkConfiguration( this IServiceCollection services, IConfiguration configuration, IHostEnvironment environment) { services.AddOptions() .Bind(configuration.GetSection(TenantResolutionOptions.SectionName)) .Validate( options => OptionsValidation.BeValidTenantResolutionOptions(options, configuration, environment.IsProduction()), "Production requires formal platform hosts, non-wildcard AllowedHosts, and trusted proxy addresses.") .ValidateOnStart(); services.Configure(options => { options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedHost | ForwardedHeaders.XForwardedProto; options.ForwardLimit = 1; options.KnownProxies.Clear(); options.KnownIPNetworks.Clear(); var resolution = configuration .GetSection(TenantResolutionOptions.SectionName) .Get() ?? new TenantResolutionOptions(); foreach (var address in resolution.TrustedProxyAddresses) { if (IPAddress.TryParse(address, out var proxy)) { options.KnownProxies.Add(proxy); } } }); services.AddOptions() .Bind(configuration.GetSection("TenantDomains")); services.AddOptions() .Bind(configuration.GetSection(CorsOptions.SectionName)) .ValidateDataAnnotations() .Validate( OptionsValidation.BeValidCorsOptions, "CORS origins must be absolute HTTP/HTTPS origins, and credentials require explicit origins.") .ValidateOnStart(); var corsOptions = configuration .GetSection(CorsOptions.SectionName) .Get() ?? new CorsOptions(); services.AddCors(options => { options.AddPolicy(CorsOptions.PolicyName, policy => { var origins = corsOptions.AllowedOrigins .Where(origin => !string.IsNullOrWhiteSpace(origin)) .Select(origin => origin.Trim().TrimEnd('/')) .Distinct(StringComparer.OrdinalIgnoreCase) .ToArray(); if (origins.Length > 0) { policy.WithOrigins(origins); } policy .WithHeaders(corsOptions.AllowedHeaders) .WithMethods(corsOptions.AllowedMethods); if (corsOptions.AllowCredentials) { policy.AllowCredentials(); } }); }); return services; } }