From 26fa8813dd3bf37f7747d235c923c2ddb4da1a89 Mon Sep 17 00:00:00 2001 From: CyberL1 Date: Mon, 10 Jun 2024 14:22:26 +0200 Subject: [PATCH] feat: error class, world checking middleware --- .../Attributes/CheckForWorldAttribute.cs | 13 ++++++ .../Controllers/Admin/ServersController.cs | 10 ++--- .../Middlewares/CheckForWorldMiddleware.cs | 41 +++++++++++++++++++ .../Modes/External/InvitesController.cs | 9 ++-- .../Modes/External/OpsController.cs | 2 + .../Modes/External/SubscriptionsController.cs | 1 + .../Modes/External/WorldsController.cs | 34 ++++++++------- .../Realms/Controllers/InvitesController.cs | 3 ++ .../Modes/Realms/Controllers/OpsController.cs | 2 + .../Controllers/SubscriptionsController.cs | 1 + .../Realms/Controllers/WorldsController.cs | 33 ++++++++------- Minecraft-Realms-Emulator/Program.cs | 2 +- .../Responses/ErrorResponse.cs | 8 ++++ 13 files changed, 118 insertions(+), 41 deletions(-) create mode 100644 Minecraft-Realms-Emulator/Attributes/CheckForWorldAttribute.cs create mode 100644 Minecraft-Realms-Emulator/Middlewares/CheckForWorldMiddleware.cs create mode 100644 Minecraft-Realms-Emulator/Responses/ErrorResponse.cs diff --git a/Minecraft-Realms-Emulator/Attributes/CheckForWorldAttribute.cs b/Minecraft-Realms-Emulator/Attributes/CheckForWorldAttribute.cs new file mode 100644 index 0000000..c96fa28 --- /dev/null +++ b/Minecraft-Realms-Emulator/Attributes/CheckForWorldAttribute.cs @@ -0,0 +1,13 @@ +using Minecraft_Realms_Emulator.Entities; + +namespace Minecraft_Realms_Emulator.Attributes +{ + [AttributeUsage(AttributeTargets.Method)] + public class CheckForWorldAttribute : Attribute + { + public bool WorldExists(World world) + { + return world != null; + } + } +} diff --git a/Minecraft-Realms-Emulator/Controllers/Admin/ServersController.cs b/Minecraft-Realms-Emulator/Controllers/Admin/ServersController.cs index 4da404d..345653d 100644 --- a/Minecraft-Realms-Emulator/Controllers/Admin/ServersController.cs +++ b/Minecraft-Realms-Emulator/Controllers/Admin/ServersController.cs @@ -27,9 +27,10 @@ namespace Minecraft_Realms_Emulator.Controllers.Admin } [HttpGet("{wId}")] + [CheckForWorld] public ActionResult GetWorld(int wId) { var world = _context.Worlds.ToList().Find(w => w.Id == wId); - + return Ok(world); } @@ -59,12 +60,10 @@ namespace Minecraft_Realms_Emulator.Controllers.Admin } [HttpPut("{wId}/open")] + [CheckForWorld] public ActionResult OpenServer(int wId) { var world = _context.Worlds.ToList().Find(w => w.Id == wId); - - if (world == null) return BadRequest("World not found"); - world.State = "OPEN"; _context.SaveChanges(); @@ -74,12 +73,11 @@ namespace Minecraft_Realms_Emulator.Controllers.Admin } [HttpPut("{wId}/close")] + [CheckForWorld] public ActionResult CloseServer(int wId) { var world = _context.Worlds.ToList().Find(w => w.Id == wId); - if (world == null) return BadRequest("World not found"); - world.State = "CLOSED"; _context.SaveChanges(); diff --git a/Minecraft-Realms-Emulator/Middlewares/CheckForWorldMiddleware.cs b/Minecraft-Realms-Emulator/Middlewares/CheckForWorldMiddleware.cs new file mode 100644 index 0000000..6e71b6b --- /dev/null +++ b/Minecraft-Realms-Emulator/Middlewares/CheckForWorldMiddleware.cs @@ -0,0 +1,41 @@ +using Minecraft_Realms_Emulator.Attributes; +using Minecraft_Realms_Emulator.Data; +using Minecraft_Realms_Emulator.Entities; +using Minecraft_Realms_Emulator.Responses; + +namespace Minecraft_Realms_Emulator.Middlewares +{ + public class CheckForWorldMiddleware(RequestDelegate next) + { + private readonly RequestDelegate _next = next; + + public async Task Invoke(HttpContext httpContext, DataContext db) + { + var endpoint = httpContext.GetEndpoint(); + var attribute = endpoint?.Metadata.GetMetadata(); + + if (attribute == null) + { + await _next(httpContext); + return; + } + + World world = db.Worlds.FirstOrDefault(w => w.Id == int.Parse(httpContext.Request.RouteValues["wId"].ToString())); + + if (!attribute.WorldExists(world)) + { + ErrorResponse errorResponse = new() + { + ErrorCode = 404, + ErrorMsg = "World not found" + }; + + httpContext.Response.StatusCode = 404; + await httpContext.Response.WriteAsJsonAsync(errorResponse); + return; + } + + await _next(httpContext); + } + } +} diff --git a/Minecraft-Realms-Emulator/Modes/External/InvitesController.cs b/Minecraft-Realms-Emulator/Modes/External/InvitesController.cs index bd14fa6..60fc586 100644 --- a/Minecraft-Realms-Emulator/Modes/External/InvitesController.cs +++ b/Minecraft-Realms-Emulator/Modes/External/InvitesController.cs @@ -94,6 +94,7 @@ namespace Minecraft_Realms_Emulator.Modes.External } [HttpPost("{wId}")] + [CheckForWorld] [CheckRealmOwner] public async Task> InvitePlayer(int wId, PlayerRequest body) { @@ -104,8 +105,6 @@ namespace Minecraft_Realms_Emulator.Modes.External var world = await _context.Worlds.Include(w => w.Players).FirstOrDefaultAsync(w => w.Id == wId); - if (world == null) return NotFound("World not found"); - // Get player UUID var playerInfo = await new HttpClient().GetFromJsonAsync($"https://api.mojang.com/users/profiles/minecraft/{body.Name}"); @@ -138,13 +137,12 @@ namespace Minecraft_Realms_Emulator.Modes.External } [HttpDelete("{wId}/invite/{uuid}")] + [CheckForWorld] [CheckRealmOwner] public async Task> DeleteInvite(int wId, string uuid) { var world = await _context.Worlds.FirstOrDefaultAsync(w => w.Id == wId); - if (world == null) return NotFound("World not found"); - var player = _context.Players.Where(p => p.World.Id == wId).FirstOrDefault(p => p.Uuid == uuid); _context.Players.Remove(player); @@ -159,6 +157,7 @@ namespace Minecraft_Realms_Emulator.Modes.External } [HttpDelete("{wId}")] + [CheckForWorld] public async Task> LeaveWorld(int wId) { string cookie = Request.Headers.Cookie; @@ -166,8 +165,6 @@ namespace Minecraft_Realms_Emulator.Modes.External var world = await _context.Worlds.FirstOrDefaultAsync(w => w.Id == wId); - if (world == null) return NotFound("World not found"); - var player = _context.Players.Where(p => p.World.Id == wId).FirstOrDefault(p => p.Uuid == playerUUID); _context.Players.Remove(player); diff --git a/Minecraft-Realms-Emulator/Modes/External/OpsController.cs b/Minecraft-Realms-Emulator/Modes/External/OpsController.cs index 2fc4321..9ea6af8 100644 --- a/Minecraft-Realms-Emulator/Modes/External/OpsController.cs +++ b/Minecraft-Realms-Emulator/Modes/External/OpsController.cs @@ -18,6 +18,7 @@ namespace Minecraft_Realms_Emulator.Modes.External } [HttpPost("{wId}/{uuid}")] + [CheckForWorld] [CheckRealmOwner] public ActionResult OpPlayer(int wId, string uuid) { @@ -47,6 +48,7 @@ namespace Minecraft_Realms_Emulator.Modes.External } [HttpDelete("{wId}/{uuid}")] + [CheckForWorld] [CheckRealmOwner] public ActionResult DeopPlayer(int wId, string uuid) { diff --git a/Minecraft-Realms-Emulator/Modes/External/SubscriptionsController.cs b/Minecraft-Realms-Emulator/Modes/External/SubscriptionsController.cs index 8847604..3ff541e 100644 --- a/Minecraft-Realms-Emulator/Modes/External/SubscriptionsController.cs +++ b/Minecraft-Realms-Emulator/Modes/External/SubscriptionsController.cs @@ -18,6 +18,7 @@ namespace Minecraft_Realms_Emulator.Modes.External _context = context; } [HttpGet("{wId}")] + [CheckForWorld] [CheckRealmOwner] public async Task> Get(int wId) { diff --git a/Minecraft-Realms-Emulator/Modes/External/WorldsController.cs b/Minecraft-Realms-Emulator/Modes/External/WorldsController.cs index 87981d9..1406fc8 100644 --- a/Minecraft-Realms-Emulator/Modes/External/WorldsController.cs +++ b/Minecraft-Realms-Emulator/Modes/External/WorldsController.cs @@ -141,6 +141,7 @@ namespace Minecraft_Realms_Emulator.Modes.External } [HttpGet("{wId}")] + [CheckForWorld] [CheckRealmOwner] public async Task> GetWorldById(int wId) { @@ -149,8 +150,6 @@ namespace Minecraft_Realms_Emulator.Modes.External var world = await _context.Worlds.Include(w => w.Players).Include(w => w.Subscription).Include(w => w.Slots).FirstOrDefaultAsync(w => w.Id == wId); - if (world?.Subscription == null) return NotFound("World not found"); - Slot activeSlot = world.Slots.Find(s => s.SlotId == world.ActiveSlot); List slots = []; @@ -211,6 +210,7 @@ namespace Minecraft_Realms_Emulator.Modes.External } [HttpPost("{wId}/initialize")] + [CheckForWorld] [CheckRealmOwner] public async Task> Initialize(int wId, WorldCreateRequest body) { @@ -221,8 +221,16 @@ namespace Minecraft_Realms_Emulator.Modes.External var world = worlds.Find(w => w.Id == wId); - if (world == null) return NotFound("World not found"); - if (world.State != nameof(StateEnum.UNINITIALIZED)) return NotFound("World already initialized"); + if (world.State != nameof(StateEnum.UNINITIALIZED)) + { + ErrorResponse errorResponse = new() + { + ErrorCode = 401, + ErrorMsg = "World already initialized", + }; + + return StatusCode(401, errorResponse); + } var subscription = new Subscription { @@ -273,6 +281,7 @@ namespace Minecraft_Realms_Emulator.Modes.External } [HttpPost("{wId}/reset")] + [CheckForWorld] [CheckRealmOwner] public ActionResult Reset(int wId) { @@ -281,6 +290,7 @@ namespace Minecraft_Realms_Emulator.Modes.External } [HttpPut("{wId}/open")] + [CheckForWorld] [CheckRealmOwner] public async Task> Open(int wId) { @@ -288,8 +298,6 @@ namespace Minecraft_Realms_Emulator.Modes.External var world = worlds.Find(w => w.Id == wId); - if (world == null) return NotFound("World not found"); - world.State = nameof(StateEnum.OPEN); _context.SaveChanges(); @@ -298,6 +306,7 @@ namespace Minecraft_Realms_Emulator.Modes.External } [HttpPut("{wId}/close")] + [CheckForWorld] [CheckRealmOwner] public async Task> Close(int wId) { @@ -305,8 +314,6 @@ namespace Minecraft_Realms_Emulator.Modes.External var world = worlds.FirstOrDefault(w => w.Id == wId); - if (world == null) return NotFound("World not found"); - world.State = nameof(StateEnum.CLOSED); _context.SaveChanges(); @@ -315,6 +322,7 @@ namespace Minecraft_Realms_Emulator.Modes.External } [HttpPost("{wId}")] + [CheckForWorld] [CheckRealmOwner] public async Task> UpdateWorld(int wId, WorldCreateRequest body) { @@ -322,8 +330,6 @@ namespace Minecraft_Realms_Emulator.Modes.External var world = worlds.Find(w => w.Id == wId); - if (world == null) return NotFound("World not found"); - world.Name = body.Name; world.Motd = body.Description; @@ -333,6 +339,7 @@ namespace Minecraft_Realms_Emulator.Modes.External } [HttpPost("{wId}/slot/{sId}")] + [CheckForWorld] [CheckRealmOwner] public async Task> UpdateSlotAsync(int wId, int sId, SlotOptionsRequest body) { @@ -356,13 +363,12 @@ namespace Minecraft_Realms_Emulator.Modes.External } [HttpPut("{wId}/slot/{sId}")] + [CheckForWorld] [CheckRealmOwner] public ActionResult SwitchSlot(int wId, int sId) { var world = _context.Worlds.Find(wId); - if (world == null) return NotFound("World not found"); - var slot = _context.Slots.Where(s => s.World.Id == wId).Where(s => s.SlotId == sId).Any(); if (!slot) @@ -397,6 +403,7 @@ namespace Minecraft_Realms_Emulator.Modes.External } [HttpGet("{wId}/backups")] + [CheckForWorld] [CheckRealmOwner] public async Task> GetBackups(int wId) { @@ -419,13 +426,12 @@ namespace Minecraft_Realms_Emulator.Modes.External } [HttpDelete("{wId}")] + [CheckForWorld] [CheckRealmOwner] public ActionResult DeleteRealm(int wId) { var world = _context.Worlds.Find(wId); - if (world == null) return NotFound("World not found"); - _context.Worlds.Remove(world); _context.SaveChanges(); diff --git a/Minecraft-Realms-Emulator/Modes/Realms/Controllers/InvitesController.cs b/Minecraft-Realms-Emulator/Modes/Realms/Controllers/InvitesController.cs index 33229f2..5421411 100644 --- a/Minecraft-Realms-Emulator/Modes/Realms/Controllers/InvitesController.cs +++ b/Minecraft-Realms-Emulator/Modes/Realms/Controllers/InvitesController.cs @@ -94,6 +94,7 @@ namespace Minecraft_Realms_Emulator.Modes.Realms.Controllers } [HttpPost("{wId}")] + [CheckForWorld] [CheckRealmOwner] [CheckActiveSubscription] public async Task> InvitePlayer(int wId, PlayerRequest body) @@ -139,6 +140,7 @@ namespace Minecraft_Realms_Emulator.Modes.Realms.Controllers } [HttpDelete("{wId}/invite/{uuid}")] + [CheckForWorld] [CheckRealmOwner] [CheckActiveSubscription] public async Task> DeleteInvite(int wId, string uuid) @@ -161,6 +163,7 @@ namespace Minecraft_Realms_Emulator.Modes.Realms.Controllers } [HttpDelete("{wId}")] + [CheckForWorld] public async Task> LeaveWorld(int wId) { string cookie = Request.Headers.Cookie; diff --git a/Minecraft-Realms-Emulator/Modes/Realms/Controllers/OpsController.cs b/Minecraft-Realms-Emulator/Modes/Realms/Controllers/OpsController.cs index 78d6c84..0d1d367 100644 --- a/Minecraft-Realms-Emulator/Modes/Realms/Controllers/OpsController.cs +++ b/Minecraft-Realms-Emulator/Modes/Realms/Controllers/OpsController.cs @@ -18,6 +18,7 @@ namespace Minecraft_Realms_Emulator.Modes.Realms.Controllers } [HttpPost("{wId}/{uuid}")] + [CheckForWorld] [CheckRealmOwner] [CheckActiveSubscription] public ActionResult OpPlayer(int wId, string uuid) @@ -48,6 +49,7 @@ namespace Minecraft_Realms_Emulator.Modes.Realms.Controllers } [HttpDelete("{wId}/{uuid}")] + [CheckForWorld] [CheckRealmOwner] [CheckActiveSubscription] public ActionResult DeopPlayer(int wId, string uuid) diff --git a/Minecraft-Realms-Emulator/Modes/Realms/Controllers/SubscriptionsController.cs b/Minecraft-Realms-Emulator/Modes/Realms/Controllers/SubscriptionsController.cs index 1f1e00b..f5bbddc 100644 --- a/Minecraft-Realms-Emulator/Modes/Realms/Controllers/SubscriptionsController.cs +++ b/Minecraft-Realms-Emulator/Modes/Realms/Controllers/SubscriptionsController.cs @@ -18,6 +18,7 @@ namespace Minecraft_Realms_Emulator.Modes.Realms.Controllers _context = context; } [HttpGet("{wId}")] + [CheckForWorld] [CheckRealmOwner] public async Task> Get(int wId) { diff --git a/Minecraft-Realms-Emulator/Modes/Realms/Controllers/WorldsController.cs b/Minecraft-Realms-Emulator/Modes/Realms/Controllers/WorldsController.cs index 5bd8386..8a12027 100644 --- a/Minecraft-Realms-Emulator/Modes/Realms/Controllers/WorldsController.cs +++ b/Minecraft-Realms-Emulator/Modes/Realms/Controllers/WorldsController.cs @@ -144,6 +144,7 @@ namespace Minecraft_Realms_Emulator.Modes.Realms.Controllers } [HttpGet("{wId}")] + [CheckForWorld] [CheckRealmOwner] public async Task> GetWorldById(int wId) { @@ -152,8 +153,6 @@ namespace Minecraft_Realms_Emulator.Modes.Realms.Controllers var world = await _context.Worlds.Include(w => w.Players).Include(w => w.Subscription).Include(w => w.Slots).FirstOrDefaultAsync(w => w.Id == wId); - if (world?.Subscription == null) return NotFound("World not found"); - Slot activeSlot = world.Slots.Find(s => s.SlotId == world.ActiveSlot); List slots = []; @@ -214,6 +213,7 @@ namespace Minecraft_Realms_Emulator.Modes.Realms.Controllers } [HttpPost("{wId}/initialize")] + [CheckForWorld] [CheckRealmOwner] public async Task> Initialize(int wId, WorldCreateRequest body) { @@ -223,9 +223,16 @@ namespace Minecraft_Realms_Emulator.Modes.Realms.Controllers var worlds = await _context.Worlds.ToListAsync(); var world = worlds.Find(w => w.Id == wId); + if (world.State != nameof(StateEnum.UNINITIALIZED)) + { + ErrorResponse errorResponse = new() + { + ErrorCode = 401, + ErrorMsg = "World already initialized", + }; - if (world == null) return NotFound("World not found"); - if (world.State != nameof(StateEnum.UNINITIALIZED)) return NotFound("World already initialized"); + return StatusCode(401, errorResponse); + } var subscription = new Subscription { @@ -289,6 +296,7 @@ namespace Minecraft_Realms_Emulator.Modes.Realms.Controllers } [HttpPost("{wId}/reset")] + [CheckForWorld] [CheckRealmOwner] [CheckActiveSubscription] public ActionResult Reset(int wId) @@ -298,6 +306,7 @@ namespace Minecraft_Realms_Emulator.Modes.Realms.Controllers } [HttpPut("{wId}/open")] + [CheckForWorld] [CheckRealmOwner] [CheckActiveSubscription] public async Task> Open(int wId) @@ -306,8 +315,6 @@ namespace Minecraft_Realms_Emulator.Modes.Realms.Controllers var world = worlds.Find(w => w.Id == wId); - if (world == null) return NotFound("World not found"); - new DockerHelper(world).StartServer(); world.State = nameof(StateEnum.OPEN); @@ -318,6 +325,7 @@ namespace Minecraft_Realms_Emulator.Modes.Realms.Controllers } [HttpPut("{wId}/close")] + [CheckForWorld] [CheckRealmOwner] [CheckActiveSubscription] public async Task> Close(int wId) @@ -326,8 +334,6 @@ namespace Minecraft_Realms_Emulator.Modes.Realms.Controllers var world = worlds.FirstOrDefault(w => w.Id == wId); - if (world == null) return NotFound("World not found"); - new DockerHelper(world).StopServer(); world.State = nameof(StateEnum.CLOSED); @@ -338,6 +344,7 @@ namespace Minecraft_Realms_Emulator.Modes.Realms.Controllers } [HttpPost("{wId}")] + [CheckForWorld] [CheckRealmOwner] [CheckActiveSubscription] public async Task> UpdateWorld(int wId, WorldCreateRequest body) @@ -346,8 +353,6 @@ namespace Minecraft_Realms_Emulator.Modes.Realms.Controllers var world = worlds.Find(w => w.Id == wId); - if (world == null) return NotFound("World not found"); - world.Name = body.Name; world.Motd = body.Description; @@ -357,6 +362,7 @@ namespace Minecraft_Realms_Emulator.Modes.Realms.Controllers } [HttpPost("{wId}/slot/{sId}")] + [CheckForWorld] [CheckRealmOwner] [CheckActiveSubscription] public async Task> UpdateSlotAsync(int wId, int sId, SlotOptionsRequest body) @@ -381,14 +387,13 @@ namespace Minecraft_Realms_Emulator.Modes.Realms.Controllers } [HttpPut("{wId}/slot/{sId}")] + [CheckForWorld] [CheckRealmOwner] [CheckActiveSubscription] public ActionResult SwitchSlot(int wId, int sId) { var world = _context.Worlds.Find(wId); - if (world == null) return NotFound("World not found"); - var slot = _context.Slots.Where(s => s.World.Id == wId).Where(s => s.SlotId == sId).Any(); if (!slot) @@ -423,6 +428,7 @@ namespace Minecraft_Realms_Emulator.Modes.Realms.Controllers } [HttpGet("{wId}/backups")] + [CheckForWorld] [CheckRealmOwner] public async Task> GetBackups(int wId) { @@ -445,13 +451,12 @@ namespace Minecraft_Realms_Emulator.Modes.Realms.Controllers } [HttpDelete("{wId}")] + [CheckForWorld] [CheckRealmOwner] public ActionResult DeleteRealm(int wId) { var world = _context.Worlds.Find(wId); - if (world == null) return NotFound("World not found"); - new DockerHelper(world).DeleteServer(); _context.Worlds.Remove(world); diff --git a/Minecraft-Realms-Emulator/Program.cs b/Minecraft-Realms-Emulator/Program.cs index 87511d7..41bda87 100644 --- a/Minecraft-Realms-Emulator/Program.cs +++ b/Minecraft-Realms-Emulator/Program.cs @@ -4,7 +4,6 @@ using Minecraft_Realms_Emulator.Data; using Minecraft_Realms_Emulator.Enums; using Minecraft_Realms_Emulator.Helpers; using Minecraft_Realms_Emulator.Middlewares; -using Minecraft_Realms_Emulator.Modes.Realms.Helpers; using Npgsql; using System.Diagnostics; using System.Reflection; @@ -125,6 +124,7 @@ app.UseMiddleware(); app.UseMiddleware(); app.UseMiddleware(); app.UseMiddleware(); +app.UseMiddleware(); Console.WriteLine($"Running in {mode.Value} mode"); app.Run(); diff --git a/Minecraft-Realms-Emulator/Responses/ErrorResponse.cs b/Minecraft-Realms-Emulator/Responses/ErrorResponse.cs new file mode 100644 index 0000000..304bffc --- /dev/null +++ b/Minecraft-Realms-Emulator/Responses/ErrorResponse.cs @@ -0,0 +1,8 @@ +namespace Minecraft_Realms_Emulator.Responses +{ + public class ErrorResponse + { + public int ErrorCode { get; set; } + public string ErrorMsg { get; set; } = string.Empty; + } +}