using Microsoft.AspNetCore.Authentication.OpenIdConnect; using Microsoft.EntityFrameworkCore; using Microsoft.OpenApi.Models; using Serilog; using Watcher.Data; using Watcher.Models; using Watcher.Services; //using Watcher.Services; //using Watcher.Workers; var builder = WebApplication.CreateBuilder(args); // Serilog konfigurieren – nur Logs, die nicht von Microsoft stammen Log.Logger = new LoggerConfiguration() .MinimumLevel.Information() .MinimumLevel.Override("Microsoft", Serilog.Events.LogEventLevel.Warning) .Enrich.FromLogContext() .WriteTo.File( "logs/watcher-.log", outputTemplate: "[{Timestamp:yyyy-MM-dd HH:mm:ss}] [{Level:u3}] {Message:lj}{NewLine}{Exception}", rollingInterval: RollingInterval.Day ) .CreateLogger(); builder.Host.UseSerilog(); // Add services to the container. builder.Services.AddControllersWithViews(); // HttpContentAccessor builder.Services.AddHttpContextAccessor(); // Storage Singleton builder.Services.AddSingleton(); builder.Services.AddSingleton(); // Background Services builder.Services.AddHostedService(); builder.Services.AddHostedService(); // Swagger API-Dokumentation builder.Services.AddSwaggerGen(options => { options.SwaggerDoc("v1", new OpenApiInfo { Title = "Watcher-Server API", Version = "v1" }); }); // ---------- Konfiguration ---------- DotNetEnv.Env.Load(); builder.Configuration .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) .AddEnvironmentVariables(); // Konfiguration laden var configuration = builder.Configuration; // ---------- DB-Kontext ---------- var dbProvider = configuration["Database:Provider"] ?? "MySQL"; var connectionString = configuration["Database:ConnectionString"]; builder.Services.AddDbContext((serviceProvider, options) => { var config = serviceProvider.GetRequiredService(); var provider = dbProvider; if (provider == "MySql") { var connStr = config.GetConnectionString("MySql") ?? config["Database:ConnectionStrings:MySql"]; options.UseMySql(connStr, ServerVersion.AutoDetect(connStr)); } else if (provider == "Sqlite") { var connStr = config.GetConnectionString("Sqlite") ?? config["Database:ConnectionStrings:Sqlite"]; options.UseSqlite(connStr); } else { throw new Exception("Unsupported database provider configured."); } }); // ---------- Authentifizierung konfigurieren ---------- // PocketID nur konfigurieren, wenn aktiviert var pocketIdSection = builder.Configuration.GetSection("Authentication:PocketID"); var pocketIdEnabled = pocketIdSection.GetValue("Enabled"); var auth = builder.Services.AddAuthentication("Cookies"); auth.AddCookie("Cookies", options => { options.LoginPath = "/Auth/Login"; options.AccessDeniedPath = "/Auth/AccessDenied"; }); builder.Services.AddAuthentication() .AddOpenIdConnect("oidc", options => { options.Authority = pocketIdSection["Authority"]; options.ClientId = pocketIdSection["ClientId"]; options.ClientSecret = pocketIdSection["ClientSecret"]; options.ResponseType = "code"; options.CallbackPath = pocketIdSection["CallbackPath"]; options.SaveTokens = true; options.GetClaimsFromUserInfoEndpoint = true; options.Scope.Clear(); options.Scope.Add("openid"); options.Scope.Add("profile"); options.Scope.Add("email"); options.Events = new OpenIdConnectEvents { OnTokenValidated = async ctx => { var db = ctx.HttpContext.RequestServices.GetRequiredService(); var principal = ctx.Principal; #pragma warning disable CS8602 // Dereference of a possibly null reference. var pocketId = principal.FindFirst("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier")?.Value; #pragma warning restore CS8602 // Dereference of a possibly null reference. var preferredUsername = principal.FindFirst("preferred_username")?.Value; var email = principal.FindFirst("email")?.Value; if (string.IsNullOrEmpty(pocketId)) return; var user = await db.Users.FirstOrDefaultAsync(u => u.OIDC_Id == pocketId); if (user == null) { user = new User { OIDC_Id = pocketId, Username = preferredUsername ?? "", Email = email, LastLogin = DateTime.UtcNow, IdentityProvider = "oidc", Password = string.Empty }; db.Users.Add(user); } else { user.LastLogin = DateTime.UtcNow; user.Username = preferredUsername ?? user.Username; user.Email = email ?? user.Email; db.Users.Update(user); } await db.SaveChangesAsync(); } }; }); var app = builder.Build(); // Migrationen anwenden (für SQLite oder andere DBs) using (var scope = app.Services.CreateScope()) { var db = scope.ServiceProvider.GetRequiredService(); db.Database.Migrate(); } // Standart-User in Datenbank schreiben using (var scope = app.Services.CreateScope()) { var db = scope.ServiceProvider.GetRequiredService(); Console.WriteLine("Checking for users..."); if (!db.Users.Any()) { Console.WriteLine("No users found, creating default user..."); var defaultUser = new User { OIDC_Id = string.Empty, Username = "admin", Email = string.Empty, LastLogin = DateTime.UtcNow, IdentityProvider = "local", Password = BCrypt.Net.BCrypt.HashPassword("changeme") }; db.Users.Add(defaultUser); db.SaveChanges(); Console.WriteLine("Default user created."); } else { Console.WriteLine("Users already exist."); } } // Configure the HTTP request pipeline. if (!app.Environment.IsDevelopment()) { app.UseExceptionHandler("/Home/Error"); app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); // 🔹 Swagger aktivieren app.UseSwagger(); app.UseSwaggerUI(options => { options.SwaggerEndpoint("/swagger/v1/swagger.json", "Watcher-Server API v1"); options.RoutePrefix = "api/v1/swagger"; }); // 🔹 Authentifizierung & Autorisierung app.UseAuthentication(); app.UseAuthorization(); // 🔹 MVC-Routing app.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}" ); app.Run();