// system usings using Microsoft.AspNetCore.HttpOverrides; using Microsoft.EntityFrameworkCore; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.IdentityModel.Tokens; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity.EntityFrameworkCore; using System.Text; // homeburger usings using agologumApi.Models; using agologumApi.Services; var builder = WebApplication.CreateBuilder(args); // make sure the jwt key exists or else abort, security issue var key = builder.Configuration["Jwt:Key"]; if(key == null) return; // connect to the sql database builder.Services.AddDbContext(options => options.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection"))); builder.Services.AddControllers(); // add our services builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); // if this grows sufficiently large we can put elsewhere // configuration for jwt authentication builder.Services.AddIdentity() .AddEntityFrameworkStores() .AddDefaultTokenProviders() .AddRoles(); builder.Services.AddAuthentication(options => { options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }).AddJwtBearer(options => { options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidateAudience = true, ValidateLifetime = true, ValidateIssuerSigningKey = true, ValidIssuer = "agologum", ValidAudience = "agologum", IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(key)), ClockSkew = TimeSpan.Zero }; }); // authorization configurations; here's where we register our permissions to policies // TODO: this suspiciously looks able to be automated through a for loop, only if we can have a static dictionary maybe though? builder.Services.AddAuthorization(options => { options.AddPolicy(Permission.SensitiveData_Read, policy => policy.RequireClaim("permission", Permission.SensitiveData_Read)); options.AddPolicy(Permission.SensitiveData_Modify, policy => policy.RequireClaim("permission", Permission.SensitiveData_Modify)); }); // configuration for behind my nginx proxy builder.Services.Configure(options => { options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto; options.KnownIPNetworks.Clear(); options.KnownProxies.Clear(); }); // Add services to the container. // Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi builder.Services.AddOpenApi(); // cors; scary needs to be fixed builder.Services.AddCors(options => { options.AddPolicy("dev", policy => { policy.AllowAnyOrigin() .AllowAnyHeader() .AllowAnyMethod(); }); // TODO: scary please fix this }); // more middleware; probably uncessary at this stage builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); // build app var app = builder.Build(); app.UseForwardedHeaders(); app.UseCors("dev"); app.UseAuthentication(); app.UseAuthorization(); // Configure the HTTP request pipeline. if (app.Environment.IsEnvironment("Development")) { app.MapOpenApi(); app.UseSwagger(); app.UseSwaggerUI(); } else { app.UseHttpsRedirection(); } app.MapControllers(); // attempt enitity-framework migrations at startup. love you stack overflow using (var scope = app.Services.CreateScope()) { var db = scope.ServiceProvider.GetRequiredService(); var retries = 10; while (retries-- > 0) { try { db.Database.Migrate(); break; } catch { Thread.Sleep(5000); } } } app.Run();