using System; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; namespace XWorld.Server.Auth { public static class AuthEndpoints { public sealed class AuthRequest { public string username { get; set; } public string password { get; set; } } public sealed class AuthResponse { public string token { get; set; } public int pid { get; set; } } public static void Map(IEndpointRouteBuilder app, AccountStore store, TokenService tokens, TimeSpan tokenTtl) { app.MapPost("/register", (AuthRequest req) => { if (req == null || string.IsNullOrWhiteSpace(req.username) || string.IsNullOrEmpty(req.password)) return Results.BadRequest(new { error = "invalid_input" }); int pid; try { pid = store.CreateAccount(req.username, req.password); } catch (DuplicateUsernameException) { return Results.Conflict(new { error = "username_taken" }); } catch (ArgumentException) { return Results.BadRequest(new { error = "invalid_input" }); } return Results.Ok(new AuthResponse { token = tokens.Issue(pid, tokenTtl), pid = pid }); }); app.MapPost("/login", (AuthRequest req) => { if (req == null || string.IsNullOrWhiteSpace(req.username) || string.IsNullOrEmpty(req.password)) return Results.BadRequest(new { error = "invalid_input" }); int? pid = store.VerifyCredentials(req.username, req.password); if (pid == null) return Results.Json(new { error = "invalid_credentials" }, statusCode: 401); return Results.Ok(new AuthResponse { token = tokens.Issue(pid.Value, tokenTtl), pid = pid.Value }); }); } } }