From 1b427607d11817b62830f5433353c62db8c62f23 Mon Sep 17 00:00:00 2001 From: Marcel Baumgartner Date: Wed, 7 Feb 2024 21:08:37 +0100 Subject: [PATCH] Fixed jwt validation error. Added node allocations editor. Small fixes --- Moonlight/Core/Services/IdentityService.cs | 2 +- Moonlight/Core/Services/Utils/JwtService.cs | 43 +++-- Moonlight/Core/UI/Components/Auth/Login.razor | 2 +- .../Core/UI/Components/Auth/Register.razor | 2 +- .../InitBackgroundService.cs | 11 ++ .../Forms/Admin/{ => Nodes}/CreateNodeForm.cs | 2 +- .../Admin/Nodes/CreateServerAllocation.cs | 12 ++ .../Forms/Admin/{ => Nodes}/UpdateNodeForm.cs | 2 +- .../Admin/Nodes/UpdateServerAllocation.cs | 12 ++ .../Servers/UI/Views/Admin/Index.razor | 1 + .../Servers/UI/Views/Admin/Nodes/View.razor | 165 +++++++++++++++++- 11 files changed, 235 insertions(+), 19 deletions(-) rename Moonlight/Features/Servers/Models/Forms/Admin/{ => Nodes}/CreateNodeForm.cs (93%) create mode 100644 Moonlight/Features/Servers/Models/Forms/Admin/Nodes/CreateServerAllocation.cs rename Moonlight/Features/Servers/Models/Forms/Admin/{ => Nodes}/UpdateNodeForm.cs (93%) create mode 100644 Moonlight/Features/Servers/Models/Forms/Admin/Nodes/UpdateServerAllocation.cs diff --git a/Moonlight/Core/Services/IdentityService.cs b/Moonlight/Core/Services/IdentityService.cs index f66570f0..cc7ceaa3 100644 --- a/Moonlight/Core/Services/IdentityService.cs +++ b/Moonlight/Core/Services/IdentityService.cs @@ -75,7 +75,7 @@ public class IdentityService if (string.IsNullOrEmpty(Token)) return; - if (!await JwtService.Validate(Token)) + if (!await JwtService.Validate(Token, "User")) return; var data = await JwtService.Decode(Token); diff --git a/Moonlight/Core/Services/Utils/JwtService.cs b/Moonlight/Core/Services/Utils/JwtService.cs index ababe258..8298cef9 100644 --- a/Moonlight/Core/Services/Utils/JwtService.cs +++ b/Moonlight/Core/Services/Utils/JwtService.cs @@ -1,5 +1,6 @@ using JWT.Algorithms; using JWT.Builder; +using JWT.Exceptions; using MoonCore.Attributes; using MoonCore.Helpers; using MoonCore.Services; @@ -43,6 +44,14 @@ public class JwtService { try { + // Without the body decode call the jwt validation would not work for some weird reason. + // It would not throw an error when the signature is invalid + _ = new JwtBuilder() + .WithSecret(ConfigService.Get().Security.Token) + .WithAlgorithm(new HMACSHA512Algorithm()) + .MustVerifySignature() + .Decode(token); + var headerJson = new JwtBuilder() .WithSecret(ConfigService.Get().Security.Token) .WithAlgorithm(new HMACSHA512Algorithm()) @@ -51,28 +60,34 @@ public class JwtService if (headerJson == null) return Task.FromResult(false); - + // Jwt type validation - if(allowedJwtTypes.Length == 0) + if (allowedJwtTypes.Length == 0) return Task.FromResult(true); - + var headerData = JsonConvert.DeserializeObject>(headerJson); - - if(headerData == null) // => Invalid header + + if (headerData == null) // => Invalid header return Task.FromResult(false); - - if(!headerData.ContainsKey("Type")) // => Invalid header, Type is missing + + if (!headerData.ContainsKey("Type")) // => Invalid header, Type is missing return Task.FromResult(false); foreach (var name in allowedJwtTypes) { - if(headerData["Type"] == name) // => Correct type found + if (headerData["Type"] == name) // => Correct type found return Task.FromResult(true); } - + // None found? Invalid type! return Task.FromResult(false); } + catch (SignatureVerificationException) + { + Logger.Warn($"A manipulated jwt has been found. Required jwt types: {string.Join(" ", allowedJwtTypes)} Jwt: {token}"); + + return Task.FromResult(false); + } catch (Exception e) { Logger.Warn(e.Message); @@ -91,11 +106,17 @@ public class JwtService .Decode(token); var data = JsonConvert.DeserializeObject>(json); - + return Task.FromResult(data)!; } - catch (Exception) + catch (SignatureVerificationException) { + return Task.FromResult(new Dictionary()); + } + catch (Exception e) + { + Logger.Warn("An unknown error occured while processing token"); + Logger.Warn(e); return Task.FromResult>(null!); } } diff --git a/Moonlight/Core/UI/Components/Auth/Login.razor b/Moonlight/Core/UI/Components/Auth/Login.razor index 489414fe..67512de3 100644 --- a/Moonlight/Core/UI/Components/Auth/Login.razor +++ b/Moonlight/Core/UI/Components/Auth/Login.razor @@ -16,7 +16,7 @@ Sign In
- Get unlimited access & earn money + Change me
diff --git a/Moonlight/Core/UI/Components/Auth/Register.razor b/Moonlight/Core/UI/Components/Auth/Register.razor index 9ed149c1..3a1b28ac 100644 --- a/Moonlight/Core/UI/Components/Auth/Register.razor +++ b/Moonlight/Core/UI/Components/Auth/Register.razor @@ -19,7 +19,7 @@ Sign Up
- Get unlimited access & earn money + change me
diff --git a/Moonlight/Features/Servers/BackgroundServices/InitBackgroundService.cs b/Moonlight/Features/Servers/BackgroundServices/InitBackgroundService.cs index c9551f0f..24763f84 100644 --- a/Moonlight/Features/Servers/BackgroundServices/InitBackgroundService.cs +++ b/Moonlight/Features/Servers/BackgroundServices/InitBackgroundService.cs @@ -1,3 +1,4 @@ +using System.Net.Sockets; using MoonCore.Abstractions; using MoonCore.Attributes; using MoonCore.Helpers; @@ -32,6 +33,16 @@ public class InitBackgroundService : BackgroundService { await nodeService.Boot(node); } + catch (HttpRequestException e) + { + if(e.InnerException is SocketException socketException) + Logger.Warn($"Unable to auto boot node '{node.Name}'. Unable to reach the daemon: {socketException.Message}"); + else + { + Logger.Warn($"An error occured while booting node '{node.Name}'"); + Logger.Warn(e); + } + } catch (Exception e) { Logger.Warn($"An error occured while booting node '{node.Name}'"); diff --git a/Moonlight/Features/Servers/Models/Forms/Admin/CreateNodeForm.cs b/Moonlight/Features/Servers/Models/Forms/Admin/Nodes/CreateNodeForm.cs similarity index 93% rename from Moonlight/Features/Servers/Models/Forms/Admin/CreateNodeForm.cs rename to Moonlight/Features/Servers/Models/Forms/Admin/Nodes/CreateNodeForm.cs index eb328bfd..b6b1e0eb 100644 --- a/Moonlight/Features/Servers/Models/Forms/Admin/CreateNodeForm.cs +++ b/Moonlight/Features/Servers/Models/Forms/Admin/Nodes/CreateNodeForm.cs @@ -1,7 +1,7 @@ using System.ComponentModel; using System.ComponentModel.DataAnnotations; -namespace Moonlight.Features.Servers.Models.Forms.Admin; +namespace Moonlight.Features.Servers.Models.Forms.Admin.Nodes; public class CreateNodeForm { diff --git a/Moonlight/Features/Servers/Models/Forms/Admin/Nodes/CreateServerAllocation.cs b/Moonlight/Features/Servers/Models/Forms/Admin/Nodes/CreateServerAllocation.cs new file mode 100644 index 00000000..d647f7d5 --- /dev/null +++ b/Moonlight/Features/Servers/Models/Forms/Admin/Nodes/CreateServerAllocation.cs @@ -0,0 +1,12 @@ +using System.ComponentModel.DataAnnotations; + +namespace Moonlight.Features.Servers.Models.Forms.Admin.Nodes; + +public class CreateServerAllocation +{ + [Required(ErrorMessage = "You need to provide a bind ip address")] + public string IpAddress { get; set; } = "0.0.0.0"; + + [Range(1, 65535, ErrorMessage = "You need to provide a valid port")] + public int Port { get; set; } +} \ No newline at end of file diff --git a/Moonlight/Features/Servers/Models/Forms/Admin/UpdateNodeForm.cs b/Moonlight/Features/Servers/Models/Forms/Admin/Nodes/UpdateNodeForm.cs similarity index 93% rename from Moonlight/Features/Servers/Models/Forms/Admin/UpdateNodeForm.cs rename to Moonlight/Features/Servers/Models/Forms/Admin/Nodes/UpdateNodeForm.cs index fdeaf112..5d84df71 100644 --- a/Moonlight/Features/Servers/Models/Forms/Admin/UpdateNodeForm.cs +++ b/Moonlight/Features/Servers/Models/Forms/Admin/Nodes/UpdateNodeForm.cs @@ -1,7 +1,7 @@ using System.ComponentModel; using System.ComponentModel.DataAnnotations; -namespace Moonlight.Features.Servers.Models.Forms.Admin; +namespace Moonlight.Features.Servers.Models.Forms.Admin.Nodes; public class UpdateNodeForm { diff --git a/Moonlight/Features/Servers/Models/Forms/Admin/Nodes/UpdateServerAllocation.cs b/Moonlight/Features/Servers/Models/Forms/Admin/Nodes/UpdateServerAllocation.cs new file mode 100644 index 00000000..e599924c --- /dev/null +++ b/Moonlight/Features/Servers/Models/Forms/Admin/Nodes/UpdateServerAllocation.cs @@ -0,0 +1,12 @@ +using System.ComponentModel.DataAnnotations; + +namespace Moonlight.Features.Servers.Models.Forms.Admin.Nodes; + +public class UpdateServerAllocation +{ + [Required(ErrorMessage = "You need to provide a bind ip address")] + public string IpAddress { get; set; } = "0.0.0.0"; + + [Range(1, 65535, ErrorMessage = "You need to provide a valid port")] + public int Port { get; set; } +} \ No newline at end of file diff --git a/Moonlight/Features/Servers/UI/Views/Admin/Index.razor b/Moonlight/Features/Servers/UI/Views/Admin/Index.razor index 1aec8e1e..50475f20 100644 --- a/Moonlight/Features/Servers/UI/Views/Admin/Index.razor +++ b/Moonlight/Features/Servers/UI/Views/Admin/Index.razor @@ -13,6 +13,7 @@ @using MoonCore.Abstractions @using MoonCore.Exceptions @using MoonCore.Helpers +@using Moonlight.Features.Servers.Models.Forms.Admin.Nodes @attribute [RequirePermission(Permission.AdminServers)] diff --git a/Moonlight/Features/Servers/UI/Views/Admin/Nodes/View.razor b/Moonlight/Features/Servers/UI/Views/Admin/Nodes/View.razor index 9ab860f4..b08795c9 100644 --- a/Moonlight/Features/Servers/UI/Views/Admin/Nodes/View.razor +++ b/Moonlight/Features/Servers/UI/Views/Admin/Nodes/View.razor @@ -1,7 +1,166 @@ @page "/admin/servers/nodes/{Id:int}" +@using BlazorTable +@using Microsoft.EntityFrameworkCore +@using MoonCore.Abstractions +@using MoonCore.Exceptions +@using MoonCoreUI.Services +@using Moonlight.Features.Servers.Entities +@using Moonlight.Features.Servers.Models.Forms.Admin.Nodes + +@inject Repository NodeRepository +@inject Repository ServerRepository +@inject Repository AllocationRepository +@inject ToastService ToastService +@inject AlertService AlertService + + + @if (Node == null) + { + + } + else + { +
+
+ +
+
+
+
+ Allocation Quick Add +
+
+
+ + - + + +
+
+
+ + +
+ + + +
+
+ + + + + +
+
+
+ } +
+ @code { - [Parameter] - public int Id { get; set; } -} + [Parameter] public int Id { get; set; } + + private ServerNode? Node; + private int AllocationStart = 2000; + private int AllocationEnd = 3000; + + private LazyLoader LazyLoader; + + private async Task Load(LazyLoader lazyLoader) + { + await lazyLoader.SetText("Loading allocations"); + + Node = NodeRepository + .Get() + .Include(x => x.Allocations) + .FirstOrDefault(x => x.Id == Id); + } + + private async Task AddAllocations() + { + int skipped = 0; + int added = 0; + + for (int i = AllocationStart; i <= AllocationEnd; i++) + { + if (Node!.Allocations.Any(x => x.Port == i)) + skipped++; + else + { + Node.Allocations.Add(new() + { + Port = i + }); + + added++; + } + } + + NodeRepository.Update(Node!); + + await ToastService.Success($"Added {added} allocations and skipped {skipped} ports due to existing allocations"); + await LazyLoader.Reload(); + } + + private Task ValidateAdd(ServerAllocation allocation) + { + if (Node!.Allocations.Any(x => x.Port == allocation.Port && x.IpAddress == allocation.IpAddress)) + throw new DisplayException("A allocation with these ip and port does already exist"); + + return Task.CompletedTask; + } + + private Task ValidateUpdate(ServerAllocation allocation) + { + if (Node!.Allocations.Any(x => x.Port == allocation.Port && x.IpAddress == allocation.IpAddress && x.Id != allocation.Id)) + throw new DisplayException("A allocation with these ip and port does already exist"); + + return Task.CompletedTask; + } + + private Task ValidateDelete(ServerAllocation allocation) + { + if (ServerRepository + .Get() + .Any(x => x.Allocations.Any(y => y.Id == allocation.Id))) + { + throw new DisplayException("A server is using this allocation. Delete the server in order to delete this allocation"); + } + + return Task.CompletedTask; + } + + private async Task DeleteAllAllocations() + { + if (!await AlertService.YesNo("Do you really want to delete all allocations?", "Yes", "No")) + return; + + foreach (var allocation in Node!.Allocations.ToArray()) // To array in order to prevent collection modified exception + { + if (ServerRepository + .Get() + .Any(x => x.Allocations.Any(y => y.Id == allocation.Id))) + { + await ToastService.Danger($"Unable to delete allocation with port {allocation.Port} due to a server using this allocation"); + continue; + } + + AllocationRepository.Delete(allocation); + } + + await ToastService.Success("Successfully deleted allocations"); + await LazyLoader.Reload(); + } + +} \ No newline at end of file