using System.Text; using FastEndpoints; using FastEndpoints.Swagger; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.IdentityModel.Tokens; using Npgsql; using SpaceGame.Api.Universe.Bootstrap; const string StartupScenarioPath = "scenarios/empty.json"; var builder = WebApplication.CreateBuilder(args); builder.Services.AddCors((options) => { options.AddDefaultPolicy((policy) => { policy .AllowAnyHeader() .AllowAnyMethod() .AllowAnyOrigin(); }); }); builder.Services .AddOptions() .Bind(builder.Configuration.GetSection("StaticData")) .Validate(options => !string.IsNullOrWhiteSpace(options.DataRoot), "StaticData:DataRoot must be configured.") .PostConfigure(options => { if (Path.IsPathRooted(options.DataRoot)) { options.DataRoot = Path.GetFullPath(options.DataRoot); return; } var candidatePaths = new[] { Path.GetFullPath(options.DataRoot), Path.GetFullPath(Path.Combine(builder.Environment.ContentRootPath, options.DataRoot)), Path.GetFullPath(Path.Combine(builder.Environment.ContentRootPath, "..", "..", options.DataRoot)), }; var resolvedPath = candidatePaths.FirstOrDefault(Directory.Exists); if (resolvedPath is null) { throw new InvalidOperationException($"StaticData:DataRoot '{options.DataRoot}' could not be resolved to an existing directory."); } options.DataRoot = resolvedPath; }) .ValidateOnStart(); builder.Services.Configure(builder.Configuration.GetSection("Balance")); builder.Services.Configure(builder.Configuration.GetSection("OrbitalSimulation")); builder.Services .AddOptions() .Bind(builder.Configuration.GetSection("Auth")) .Validate(options => !string.IsNullOrWhiteSpace(options.ConnectionString), "Auth:ConnectionString must be configured.") .ValidateOnStart(); builder.Services .AddOptions() .Bind(builder.Configuration.GetSection("Jwt")) .Validate(options => !string.IsNullOrWhiteSpace(options.SigningKey), "Jwt:SigningKey must be configured.") .ValidateOnStart(); var jwtOptions = builder.Configuration.GetSection("Jwt").Get() ?? new JwtOptions(); var signingKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtOptions.SigningKey)); builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidateAudience = true, ValidateIssuerSigningKey = true, ValidateLifetime = true, ValidIssuer = jwtOptions.Issuer, ValidAudience = jwtOptions.Audience, IssuerSigningKey = signingKey, ClockSkew = TimeSpan.FromSeconds(30), }; }); builder.Services .AddAuthorizationBuilder() .AddPolicy(AuthPolicyNames.AdminAccess, policy => { policy.RequireAuthenticatedUser(); policy.RequireRole(AuthRoleNames.Admin); }) .AddPolicy(AuthPolicyNames.GmAccess, policy => { policy.RequireAuthenticatedUser(); policy.RequireRole(AuthRoleNames.Gm); }); builder.Services.AddHttpContextAccessor(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton((serviceProvider) => { var authOptions = serviceProvider.GetRequiredService>(); return new NpgsqlDataSourceBuilder(authOptions.Value.ConnectionString).Build(); }); builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddTransient(); builder.Services.AddTransient(); builder.Services.AddTransient(); builder.Services.AddTransient(); builder.Services.AddTransient(); builder.Services.AddTransient(); builder.Services.AddTransient(); builder.Services.AddTransient(); builder.Services.AddTransient(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddHostedService(); builder.Services.AddFastEndpoints(); builder.Services.SwaggerDocument(); var app = builder.Build(); await app.Services.GetRequiredService().EnsureSchemaAsync(CancellationToken.None); if (builder.Environment.IsDevelopment()) { await app.Services.GetRequiredService().SeedAsync(CancellationToken.None); app.Services.GetRequiredService().LoadFromScenario(StartupScenarioPath); } app.UseCors(); app.UseAuthentication(); app.UseAuthorization(); app.UseFastEndpoints(); app.UseSwaggerGen(); app.Run();