using VPNAuth.Server; using VPNAuth.Server.Database; using VPNAuth.Server.Responses; Config.CreateIfNotExists(); var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddRazorPages(); var app = builder.Build(); // Configure the HTTP request pipeline. if (!app.Environment.IsDevelopment()) { app.UseExceptionHandler("/Error"); // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(new StaticFileOptions { RequestPath = "/static" }); app.UseRouting(); app.MapGet("/accept-auth/{id}", async (HttpContext context, int id) => { using var db = new Database(); var authRequest = db.AuthRequests.Find(id); if (authRequest == null || authRequest.Accepted) { context.Response.StatusCode = StatusCodes.Status404NotFound; return; } if (authRequest.Username != context.GetUser()?.Username) { context.Response.StatusCode = StatusCodes.Status403Forbidden; return; } authRequest.Accepted = true; db.SaveChanges(); var config = Config.Read(); context.Response.StatusCode = StatusCodes.Status302Found; context.Response.Headers["Location"] = config.FindApp(authRequest.ClientId)!.RedirectUri! + "?code=" + authRequest.Code + "&state=" + authRequest.State; }); app.MapPost("/access-token", async (HttpContext context) => { var config = Config.Read(); if (context.Request.Form["grant_type"] != "authorization_code") { context.Response.StatusCode = StatusCodes.Status400BadRequest; return; } var clientSecret = config.FindApp(context.Request.Form["client_id"]!)!.Secret; // FIXME: null pointer if (clientSecret != null && clientSecret != context.Request.Form["client_secret"]) { context.Response.StatusCode = StatusCodes.Status403Forbidden; return; } using var db = new Database(); var authRequest = db.AuthRequests .Where(request => request.Code == context.Request.Form["code"].ToString()) .ToList() .FirstOrDefault(); if (authRequest == null) { context.Response.StatusCode = StatusCodes.Status404NotFound; return; } // TODO: validate code verifier -> context.Request.Form["code_verifier"] var accessTokenEntry = db.AccessTokens.Add(new AccessToken { ClientId = authRequest.ClientId, Scopes = authRequest.Scopes, CreationTime = DateTime.Now, Token = PkceUtils.GenerateToken(), Username = authRequest.Username }); db.SaveChanges(); await context.Response.WriteAsJsonAsync(new Token { AccessToken = accessTokenEntry.Entity.Token, TokenType = "Bearer", Expires = 0 // TODO: change to actual value }); }); app.MapPost("/user-info-settings", async (HttpContext context) => { using var db = new Database(); ConfigUser? configUser = context.GetUser(); if (configUser == null) { context.Response.StatusCode = StatusCodes.Status401Unauthorized; } UserInformation? userInformation = db.UserInformation .Where(user => user.Sub == configUser!.Username) .ToList() .FirstOrDefault() ?? db.Add(new UserInformation { Sub = configUser!.Username }).Entity; if (context.Request.Form.ContainsKey("given-name")) userInformation.GivenName = context.Request.Form["given-name"]!; if (context.Request.Form.ContainsKey("family-name")) userInformation.FamilyName = context.Request.Form["family-name"]!; if (context.Request.Form.ContainsKey("preferred-username")) userInformation.PreferredUsername = context.Request.Form["preferred-username"]!; if (context.Request.Form.ContainsKey("email")) userInformation.Email = context.Request.Form["email"]!; if (context.Request.Form.ContainsKey("picture")) userInformation.Picture = context.Request.Form["picture"]!; userInformation.Name = userInformation.GivenName + " " + userInformation.FamilyName; db.SaveChanges(); }); app.Map("/user-info", (HttpContext context) => { if (context.Request.Method != "GET" && context.Request.Method != "POST") { context.Response.StatusCode = StatusCodes.Status405MethodNotAllowed; return; } var tokenHeader = context.Request.Headers["Authorization"].First()?.Split(" "); if (tokenHeader?.Length == 1 || tokenHeader?[0] != "Bearer") { context.Response.StatusCode = StatusCodes.Status400BadRequest; return; } if (tokenHeader.Length >= 2) { context.Response.StatusCode = StatusCodes.Status401Unauthorized; return; } using var db = new Database(); var tokenDbEntry = db.AccessTokens .Where(tokenEntry => tokenEntry.Token == tokenHeader[1]) .ToList() .FirstOrDefault(); if (tokenDbEntry == null) { context.Response.StatusCode = StatusCodes.Status403Forbidden; return; } var userInformation = db.UserInformation .Where(entry => entry.Sub == tokenDbEntry.Username) .ToList() .FirstOrDefault(); if (userInformation == null) { context.Response.StatusCode = StatusCodes.Status204NoContent; return; } context.Response.WriteAsJsonAsync(new UserInfo { Email = userInformation.Email, GivenName = userInformation.GivenName, FamilyName = userInformation.FamilyName, Name = userInformation.Name, Picture = userInformation.Picture, PreferredUsername = userInformation.PreferredUsername, Sub = userInformation.Sub }); }); app.MapStaticAssets(); app.MapRazorPages() .WithStaticAssets(); app.Run("http://localhost:8080");